mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-12-14 08:34:25 +03:00
Merge pull request #3480 from urbit/jb/term-efficiency
vere: refactors terminal output implementation for efficiency
This commit is contained in:
commit
26d27e4215
@ -136,14 +136,6 @@
|
||||
c3_w pid_w; // pid of checkpoint process
|
||||
} u3_save;
|
||||
|
||||
/* u3_ubuf: unix tty i/o buffer.
|
||||
*/
|
||||
typedef struct _u3_ubuf {
|
||||
struct _u3_ubuf* nex_u;
|
||||
c3_w len_w;
|
||||
c3_y hun_y[0]; // bytes to send
|
||||
} u3_ubuf;
|
||||
|
||||
/* u3_utat: unix terminal state.
|
||||
*/
|
||||
typedef struct {
|
||||
@ -153,9 +145,10 @@
|
||||
} siz;
|
||||
|
||||
struct {
|
||||
c3_w* lin_w; // current line (utf32)
|
||||
c3_w len_w; // length of current line
|
||||
c3_w sap_w; // escape chars in current line
|
||||
c3_y* lin_y; // current line (utf8)
|
||||
c3_w byt_w; // utf8 line-length
|
||||
c3_w wor_w; // utf32 line-length
|
||||
c3_w sap_w; // escape chars in line
|
||||
c3_w cus_w; // cursor position
|
||||
} mir;
|
||||
|
||||
@ -190,25 +183,26 @@
|
||||
/* u2_utfo: unix terminfo strings.
|
||||
*/
|
||||
typedef struct {
|
||||
// disabled, currently unused
|
||||
//
|
||||
// struct {
|
||||
// uv_buf_t kcuu1_u; // key_up
|
||||
// uv_buf_t kcud1_u; // key_down
|
||||
// uv_buf_t kcub1_u; // key_back
|
||||
// uv_buf_t kcuf1_u; // key_forward
|
||||
// } inn;
|
||||
struct {
|
||||
const c3_y* kcuu1_y; // key_up
|
||||
const c3_y* kcud1_y; // key_down
|
||||
const c3_y* kcub1_y; // key_back
|
||||
const c3_y* kcuf1_y; // key_forward
|
||||
c3_w max_w; // maximum input sequence length
|
||||
} inn;
|
||||
struct {
|
||||
const c3_y* clear_y; // clear_screen
|
||||
const c3_y* el_y; // clr_bol clear to beginning
|
||||
// const c3_y* el1_y; // clr_eol clear to end
|
||||
const c3_y* ed_y; // clear to end of screen
|
||||
const c3_y* bel_y; // bel sound bell
|
||||
const c3_y* cub1_y; // parm_left
|
||||
const c3_y* cuf1_y; // parm_right
|
||||
const c3_y* cuu1_y; // parm_up
|
||||
const c3_y* cud1_y; // parm_down
|
||||
// const c3_y* cub_y; // parm_left_cursor #num
|
||||
// const c3_y* cuf_y; // parm_right_cursor #num
|
||||
uv_buf_t clear_u; // clear_screen
|
||||
uv_buf_t el_u; // clr_bol clear to beginning
|
||||
// uv_buf_t el1_u; // clr_eol clear to end
|
||||
uv_buf_t ed_u; // clear to end of screen
|
||||
uv_buf_t bel_u; // bel sound bell
|
||||
uv_buf_t cub1_u; // parm_left
|
||||
uv_buf_t cuf1_u; // parm_right
|
||||
uv_buf_t cuu1_u; // parm_up
|
||||
uv_buf_t cud1_u; // parm_down
|
||||
// uv_buf_t cub_u; // parm_left_cursor #num
|
||||
// uv_buf_t cuf_u; // parm_right_cursor #num
|
||||
} out;
|
||||
} u3_utfo;
|
||||
|
||||
|
@ -13,6 +13,14 @@
|
||||
#include "all.h"
|
||||
#include "vere/vere.h"
|
||||
|
||||
// macros for string literal args/buffers
|
||||
//
|
||||
// since (sizeof(s) - 1) is used for vector length, parameters
|
||||
// must be appropriately typed. use with care!
|
||||
//
|
||||
#define TERM_LIT(s) sizeof(s) - 1, (const c3_y*)(s)
|
||||
#define TERM_LIT_BUF(s) uv_buf_init(s, sizeof(s) - 1)
|
||||
|
||||
static u3_utty* _term_main();
|
||||
static void _term_read_cb(uv_stream_t* tcp_u,
|
||||
ssize_t siz_i,
|
||||
@ -143,62 +151,36 @@ u3_term_log_init(void)
|
||||
uv_pipe_open(&(uty_u->pop_u), uty_u->fid_i);
|
||||
}
|
||||
|
||||
// Load terminfo strings.
|
||||
// configure output escape sequences
|
||||
//
|
||||
// our requirements are minimal here, so we bypass terminfo
|
||||
// and simply use constant sequences.
|
||||
//
|
||||
{
|
||||
c3_w len_w;
|
||||
|
||||
uty_u->ufo_u.inn.max_w = 0;
|
||||
|
||||
// escape sequences we use
|
||||
// (as reported by the terminfo database we bundled)
|
||||
//
|
||||
{
|
||||
uty_u->ufo_u.out.clear_y = (const c3_y*)"\033[H\033[2J";
|
||||
uty_u->ufo_u.out.el_y = (const c3_y*)"\033[K";
|
||||
// uty_u->ufo_u.out.el1_y = (const c3_y*)"\033[1K";
|
||||
uty_u->ufo_u.out.ed_y = (const c3_y*)"\033[J";
|
||||
uty_u->ufo_u.out.bel_y = (const c3_y*)"\x7";
|
||||
uty_u->ufo_u.out.cub1_y = (const c3_y*)"\x8";
|
||||
uty_u->ufo_u.out.cuf1_y = (const c3_y*)"\033[C";
|
||||
uty_u->ufo_u.out.cuu1_y = (const c3_y*)"\033[A";
|
||||
uty_u->ufo_u.out.cud1_y = (const c3_y*)"\xa";
|
||||
// uty_u->ufo_u.out.cub_y = (const c3_y*)"\033[%p1%dD";
|
||||
// uty_u->ufo_u.out.cuf_y = (const c3_y*)"\033[%p1%dC";
|
||||
}
|
||||
|
||||
// NB: terminfo reports the wrong sequence for arrow keys on xterms.
|
||||
//
|
||||
{
|
||||
uty_u->ufo_u.inn.kcuu1_y = (const c3_y*)"\033[A"; // terminfo reports "\033OA"
|
||||
uty_u->ufo_u.inn.kcud1_y = (const c3_y*)"\033[B"; // terminfo reports "\033OB"
|
||||
uty_u->ufo_u.inn.kcuf1_y = (const c3_y*)"\033[C"; // terminfo reports "\033OC"
|
||||
uty_u->ufo_u.inn.kcub1_y = (const c3_y*)"\033[D"; // terminfo reports "\033OD"
|
||||
}
|
||||
|
||||
uty_u->ufo_u.inn.max_w = 0;
|
||||
if ( (len_w = strlen((c3_c*)uty_u->ufo_u.inn.kcuu1_y)) >
|
||||
uty_u->ufo_u.inn.max_w )
|
||||
{
|
||||
uty_u->ufo_u.inn.max_w = len_w;
|
||||
}
|
||||
if ( (len_w = strlen((c3_c*)uty_u->ufo_u.inn.kcud1_y)) >
|
||||
uty_u->ufo_u.inn.max_w )
|
||||
{
|
||||
uty_u->ufo_u.inn.max_w = len_w;
|
||||
}
|
||||
if ( (len_w = strlen((c3_c*)uty_u->ufo_u.inn.kcub1_y)) >
|
||||
uty_u->ufo_u.inn.max_w )
|
||||
{
|
||||
uty_u->ufo_u.inn.max_w = len_w;
|
||||
}
|
||||
if ( (len_w = strlen((c3_c*)uty_u->ufo_u.inn.kcuf1_y)) >
|
||||
uty_u->ufo_u.inn.max_w )
|
||||
{
|
||||
uty_u->ufo_u.inn.max_w = len_w;
|
||||
}
|
||||
uty_u->ufo_u.out.clear_u = TERM_LIT_BUF("\033[H\033[2J");
|
||||
uty_u->ufo_u.out.el_u = TERM_LIT_BUF("\033[K");
|
||||
// uty_u->ufo_u.out.el1_u = TERM_LIT_BUF("\033[1K");
|
||||
uty_u->ufo_u.out.ed_u = TERM_LIT_BUF("\033[J");
|
||||
uty_u->ufo_u.out.bel_u = TERM_LIT_BUF("\x7");
|
||||
uty_u->ufo_u.out.cub1_u = TERM_LIT_BUF("\x8");
|
||||
uty_u->ufo_u.out.cuf1_u = TERM_LIT_BUF("\033[C");
|
||||
uty_u->ufo_u.out.cuu1_u = TERM_LIT_BUF("\033[A");
|
||||
uty_u->ufo_u.out.cud1_u = TERM_LIT_BUF("\xa");
|
||||
// uty_u->ufo_u.out.cub_u = TERM_LIT_BUF("\033[%p1%dD");
|
||||
// uty_u->ufo_u.out.cuf_u = TERM_LIT_BUF("\033[%p1%dC");
|
||||
}
|
||||
|
||||
// configure input escape sequences
|
||||
//
|
||||
// NB: terminfo reports the wrong sequence for arrow keys on xterms.
|
||||
// disabled, currently unused
|
||||
// {
|
||||
// uty_u->ufo_u.inn.kcuu1_u = TERM_LIT_BUF("\033[A"); // terminfo reports "\033OA"
|
||||
// uty_u->ufo_u.inn.kcud1_u = TERM_LIT_BUF("\033[B"); // terminfo reports "\033OB"
|
||||
// uty_u->ufo_u.inn.kcuf1_u = TERM_LIT_BUF("\033[C"); // terminfo reports "\033OC"
|
||||
// uty_u->ufo_u.inn.kcub1_u = TERM_LIT_BUF("\033[D"); // terminfo reports "\033OD"
|
||||
// }
|
||||
|
||||
// Load old terminal state to restore.
|
||||
//
|
||||
{
|
||||
@ -229,8 +211,10 @@ u3_term_log_init(void)
|
||||
// Initialize mirror and accumulator state.
|
||||
//
|
||||
{
|
||||
uty_u->tat_u.mir.lin_w = 0;
|
||||
uty_u->tat_u.mir.len_w = 0;
|
||||
uty_u->tat_u.mir.lin_y = 0;
|
||||
uty_u->tat_u.mir.byt_w = 0;
|
||||
uty_u->tat_u.mir.wor_w = 0;
|
||||
uty_u->tat_u.mir.sap_w = 0;
|
||||
uty_u->tat_u.mir.cus_w = 0;
|
||||
|
||||
uty_u->tat_u.esc.ape = c3n;
|
||||
@ -307,7 +291,9 @@ u3_term_log_exit(void)
|
||||
}
|
||||
}
|
||||
|
||||
uv_close((uv_handle_t*)&u3_Host.uty_u->pop_u, 0);
|
||||
if ( u3_Host.uty_u ) {
|
||||
uv_close((uv_handle_t*)&u3_Host.uty_u->pop_u, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* _term_tcsetattr(): tcsetattr w/retry on EINTR.
|
||||
@ -331,25 +317,13 @@ _term_tcsetattr(c3_i fil_i, c3_i act_i, const struct termios* tms_u)
|
||||
return ret_i;
|
||||
}
|
||||
|
||||
/* _term_it_buf(): create a data buffer.
|
||||
*/
|
||||
static u3_ubuf*
|
||||
_term_it_buf(c3_w len_w, const c3_y* hun_y)
|
||||
{
|
||||
u3_ubuf* buf_u = c3_malloc(len_w + sizeof(*buf_u));
|
||||
|
||||
buf_u->len_w = len_w;
|
||||
memcpy(buf_u->hun_y, hun_y, len_w);
|
||||
|
||||
buf_u->nex_u = 0;
|
||||
return buf_u;
|
||||
}
|
||||
|
||||
/* _term_write_cb(): general write callback.
|
||||
/* _term_it_write_cb(): general write callback.
|
||||
*/
|
||||
static void
|
||||
_term_write_cb(uv_write_t* wri_u, c3_i sas_i)
|
||||
_term_it_write_cb(uv_write_t* wri_u, c3_i sas_i)
|
||||
{
|
||||
// write failure is logged, but otherwise ignored.
|
||||
//
|
||||
if ( 0 != sas_i ) {
|
||||
u3l_log("term: write: %s\n", uv_strerror(sas_i));
|
||||
}
|
||||
@ -358,87 +332,102 @@ _term_write_cb(uv_write_t* wri_u, c3_i sas_i)
|
||||
c3_free(wri_u);
|
||||
}
|
||||
|
||||
/* _term_it_write_buf(): write buffer uv style.
|
||||
/* _term_it_write(): write libuv buffer, freeing pointer.
|
||||
*/
|
||||
static void
|
||||
_term_it_write_buf(u3_utty* uty_u, uv_buf_t buf_u)
|
||||
_term_it_write(u3_utty* uty_u,
|
||||
uv_buf_t* buf_u,
|
||||
void* ptr_v)
|
||||
{
|
||||
uv_write_t* wri_u = c3_malloc(sizeof(uv_write_t));
|
||||
wri_u->data = buf_u.base;
|
||||
|
||||
c3_w ret_w;
|
||||
if ( 0 != (ret_w = uv_write(wri_u,
|
||||
(uv_stream_t*)&(uty_u->pop_u),
|
||||
&buf_u, 1,
|
||||
_term_write_cb)) )
|
||||
{
|
||||
u3l_log("term: write: %s\n", uv_strerror(ret_w));
|
||||
}
|
||||
}
|
||||
|
||||
/* _term_it_write_old(): write buffer, transferring pointer.
|
||||
*/
|
||||
static void
|
||||
_term_it_write_old(u3_utty* uty_u,
|
||||
u3_ubuf* old_u)
|
||||
{
|
||||
uv_buf_t buf_u;
|
||||
|
||||
// XX extra copy here due to old code. Use hbod as base directly.
|
||||
// work off a local copy of the buffer, in case we need
|
||||
// to manipulate the length/pointer
|
||||
//
|
||||
{
|
||||
c3_y* buf_y = c3_malloc(old_u->len_w);
|
||||
uv_buf_t fub_u = { .base = buf_u->base, .len = buf_u->len };
|
||||
uv_stream_t* han_u = (uv_stream_t*)&(uty_u->pop_u);
|
||||
c3_i ret_i;
|
||||
|
||||
memcpy(buf_y, old_u->hun_y, old_u->len_w);
|
||||
buf_u = uv_buf_init((c3_c*)buf_y, old_u->len_w);
|
||||
// try to write synchronously
|
||||
//
|
||||
while ( 1 ) {
|
||||
ret_i = uv_try_write(han_u, &fub_u, 1);
|
||||
|
||||
c3_free(old_u);
|
||||
if ( (ret_i > 0) && (ret_i < fub_u.len) ) {
|
||||
fub_u.len -= ret_i;
|
||||
fub_u.base += ret_i;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// cue an async write if necessary
|
||||
//
|
||||
if ( UV_EAGAIN == ret_i ) {
|
||||
uv_write_t* wri_u = c3_malloc(sizeof(*wri_u));
|
||||
wri_u->data = ptr_v;
|
||||
|
||||
// invoke callback manually on error
|
||||
//
|
||||
if ( (ret_i = uv_write(wri_u, han_u, &fub_u, 1, _term_it_write_cb)) ) {
|
||||
_term_it_write_cb(wri_u, ret_i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// synchronous write failure is logged, but otherwise ignored
|
||||
//
|
||||
if ( ret_i < 0 ) {
|
||||
u3l_log("term: write: %s\n", uv_strerror(ret_i));
|
||||
}
|
||||
|
||||
c3_free(ptr_v);
|
||||
}
|
||||
_term_it_write_buf(uty_u, buf_u);
|
||||
}
|
||||
|
||||
/* _term_it_write_bytes(): write bytes, retaining pointer.
|
||||
/* _term_it_dump_buf(): write static buffer.
|
||||
*/
|
||||
static void
|
||||
_term_it_write_bytes(u3_utty* uty_u,
|
||||
c3_w len_w,
|
||||
const c3_y* hun_y)
|
||||
_term_it_dump_buf(u3_utty* uty_u,
|
||||
uv_buf_t* buf_u)
|
||||
{
|
||||
_term_it_write_old(uty_u, _term_it_buf(len_w, hun_y));
|
||||
_term_it_write(uty_u, buf_u, 0);
|
||||
}
|
||||
|
||||
/* _term_it_write_txt(): write null-terminated string, retaining pointer.
|
||||
/* _term_it_dump(): write static vector.
|
||||
*/
|
||||
static void
|
||||
_term_it_write_txt(u3_utty* uty_u,
|
||||
const c3_y* hun_y)
|
||||
_term_it_dump(u3_utty* uty_u,
|
||||
c3_w len_w,
|
||||
const c3_y* hun_y)
|
||||
{
|
||||
_term_it_write_bytes(uty_u, strlen((const c3_c*)hun_y), hun_y);
|
||||
uv_buf_t buf_u = uv_buf_init((c3_c*)hun_y, len_w);
|
||||
_term_it_dump_buf(uty_u, &buf_u);
|
||||
}
|
||||
|
||||
/* _term_it_write_str(): write null-terminated string, retaining pointer.
|
||||
/* _term_it_send(): write dynamic vector, freeing pointer.
|
||||
*/
|
||||
static void
|
||||
_term_it_write_str(u3_utty* uty_u,
|
||||
const c3_c* str_c)
|
||||
_term_it_send(u3_utty* uty_u,
|
||||
c3_w len_w,
|
||||
const c3_y* hun_y)
|
||||
{
|
||||
_term_it_write_txt(uty_u, (const c3_y*) str_c);
|
||||
uv_buf_t buf_u = uv_buf_init((c3_c*)hun_y, len_w);
|
||||
_term_it_write(uty_u, &buf_u, (void*)hun_y);
|
||||
}
|
||||
|
||||
/* _term_it_show_wide(): show wide text, retaining.
|
||||
/* _term_it_send_cord(): write a cord.
|
||||
*/
|
||||
static void
|
||||
_term_it_show_wide(u3_utty* uty_u, c3_w len_w, c3_w* txt_w)
|
||||
_term_it_send_cord(u3_utty* uty_u,
|
||||
u3_atom txt)
|
||||
{
|
||||
u3_noun wad = u3i_words(len_w, txt_w);
|
||||
u3_noun txt = u3do("tuft", wad);
|
||||
c3_c* txt_c = u3r_string(txt);
|
||||
c3_w len_w = u3r_met(3, txt);
|
||||
c3_y* hun_y = c3_malloc(len_w);
|
||||
u3r_bytes(0, len_w, hun_y, txt);
|
||||
|
||||
_term_it_send(uty_u, len_w, hun_y);
|
||||
|
||||
_term_it_write_str(uty_u, txt_c);
|
||||
c3_free(txt_c);
|
||||
u3z(txt);
|
||||
|
||||
uty_u->tat_u.mir.cus_w += len_w;
|
||||
}
|
||||
|
||||
/* _term_it_show_clear(): clear to the beginning of the current line.
|
||||
@ -447,10 +436,10 @@ static void
|
||||
_term_it_show_clear(u3_utty* uty_u)
|
||||
{
|
||||
if ( uty_u->tat_u.siz.col_l ) {
|
||||
_term_it_write_str(uty_u, "\r");
|
||||
_term_it_write_txt(uty_u, uty_u->ufo_u.out.el_y);
|
||||
_term_it_dump(uty_u, TERM_LIT("\r"));
|
||||
_term_it_dump_buf(uty_u, &uty_u->ufo_u.out.el_u);
|
||||
|
||||
uty_u->tat_u.mir.len_w = 0;
|
||||
uty_u->tat_u.mir.wor_w = 0;
|
||||
uty_u->tat_u.mir.cus_w = 0;
|
||||
}
|
||||
}
|
||||
@ -460,7 +449,7 @@ _term_it_show_clear(u3_utty* uty_u)
|
||||
static void
|
||||
_term_it_show_blank(u3_utty* uty_u)
|
||||
{
|
||||
_term_it_write_txt(uty_u, uty_u->ufo_u.out.clear_y);
|
||||
_term_it_dump_buf(uty_u, &uty_u->ufo_u.out.clear_u);
|
||||
}
|
||||
|
||||
/* _term_it_show_cursor(): set current line, transferring pointer.
|
||||
@ -468,42 +457,55 @@ _term_it_show_blank(u3_utty* uty_u)
|
||||
static void
|
||||
_term_it_show_cursor(u3_utty* uty_u, c3_w cur_w)
|
||||
{
|
||||
c3_w cus_w = uty_u->tat_u.mir.cus_w;
|
||||
c3_w dif_w;
|
||||
|
||||
//NOTE assumes all styled text precedes the cursor. drum enforces this.
|
||||
//
|
||||
cur_w = cur_w + uty_u->tat_u.mir.sap_w;
|
||||
cur_w += uty_u->tat_u.mir.sap_w;
|
||||
|
||||
if ( cur_w < uty_u->tat_u.mir.cus_w ) {
|
||||
c3_w dif_w = (uty_u->tat_u.mir.cus_w - cur_w);
|
||||
if ( cur_w < cus_w ) {
|
||||
dif_w = cus_w - cur_w;
|
||||
|
||||
while ( dif_w-- ) {
|
||||
_term_it_write_txt(uty_u, uty_u->ufo_u.out.cub1_y);
|
||||
_term_it_dump_buf(uty_u, &uty_u->ufo_u.out.cub1_u);
|
||||
}
|
||||
}
|
||||
else if ( cur_w > uty_u->tat_u.mir.cus_w ) {
|
||||
c3_w dif_w = (cur_w - uty_u->tat_u.mir.cus_w);
|
||||
else if ( cur_w > cus_w ) {
|
||||
dif_w = cur_w - cus_w;
|
||||
|
||||
while ( dif_w-- ) {
|
||||
_term_it_write_txt(uty_u, uty_u->ufo_u.out.cuf1_y);
|
||||
_term_it_dump_buf(uty_u, &uty_u->ufo_u.out.cuf1_u);
|
||||
}
|
||||
}
|
||||
|
||||
uty_u->tat_u.mir.cus_w = cur_w;
|
||||
}
|
||||
|
||||
/* _term_it_show_line(): set current line
|
||||
/* _term_it_show_line(): render current line.
|
||||
*/
|
||||
static void
|
||||
_term_it_show_line(u3_utty* uty_u, c3_w* lin_w, c3_w len_w, c3_w sap_w)
|
||||
_term_it_show_line(u3_utty* uty_u, c3_w wor_w, c3_w sap_w)
|
||||
{
|
||||
_term_it_show_wide(uty_u, len_w, lin_w);
|
||||
u3_utat* tat_u = &uty_u->tat_u;
|
||||
|
||||
if ( lin_w != uty_u->tat_u.mir.lin_w ) {
|
||||
if ( uty_u->tat_u.mir.lin_w ) {
|
||||
c3_free(uty_u->tat_u.mir.lin_w);
|
||||
}
|
||||
uty_u->tat_u.mir.lin_w = lin_w;
|
||||
// we have to reallocate the current line on write,
|
||||
// or we have a data race if a) the write is async,
|
||||
// and b) a new output line arrives before the write completes.
|
||||
//
|
||||
{
|
||||
c3_w len_w = tat_u->mir.byt_w;
|
||||
c3_y* hun_y = c3_malloc(len_w);
|
||||
memcpy(hun_y, tat_u->mir.lin_y, len_w);
|
||||
|
||||
_term_it_send(uty_u, len_w, hun_y);
|
||||
}
|
||||
uty_u->tat_u.mir.len_w = len_w;
|
||||
uty_u->tat_u.mir.sap_w = sap_w;
|
||||
|
||||
// XX refactor to avoid updating state
|
||||
//
|
||||
tat_u->mir.cus_w += wor_w;
|
||||
tat_u->mir.wor_w = wor_w;
|
||||
tat_u->mir.sap_w = sap_w;
|
||||
}
|
||||
|
||||
/* _term_it_refresh_line(): refresh current line.
|
||||
@ -511,25 +513,81 @@ _term_it_show_line(u3_utty* uty_u, c3_w* lin_w, c3_w len_w, c3_w sap_w)
|
||||
static void
|
||||
_term_it_refresh_line(u3_utty* uty_u)
|
||||
{
|
||||
c3_w len_w = uty_u->tat_u.mir.len_w;
|
||||
c3_w sap_w = uty_u->tat_u.mir.sap_w;
|
||||
c3_w cus_w = uty_u->tat_u.mir.cus_w;
|
||||
u3_utat* tat_u = &uty_u->tat_u;
|
||||
c3_w wor_w = tat_u->mir.wor_w;
|
||||
c3_w sap_w = tat_u->mir.sap_w;
|
||||
c3_w cus_w = tat_u->mir.cus_w;
|
||||
|
||||
_term_it_show_clear(uty_u);
|
||||
_term_it_show_line(uty_u, uty_u->tat_u.mir.lin_w, len_w, sap_w);
|
||||
_term_it_show_line(uty_u, wor_w, sap_w);
|
||||
_term_it_show_cursor(uty_u, cus_w);
|
||||
}
|
||||
|
||||
/* _term_it_set_line(): set current line.
|
||||
*/
|
||||
static void
|
||||
_term_it_set_line(u3_utty* uty_u,
|
||||
c3_w* lin_w,
|
||||
c3_w wor_w,
|
||||
c3_w sap_w)
|
||||
{
|
||||
u3_utat* tat_u = &uty_u->tat_u;
|
||||
c3_y* hun_y = (c3_y*)lin_w;
|
||||
c3_w byt_w = 0;
|
||||
|
||||
// convert lin_w in-place from utf-32 to utf-8
|
||||
//
|
||||
// (this is just a hand-translation of +tuft)
|
||||
// XX refactor for use here and in a jet
|
||||
//
|
||||
{
|
||||
c3_w car_w, i_w;
|
||||
|
||||
for ( i_w = 0; i_w < wor_w; i_w++ ) {
|
||||
car_w = lin_w[i_w];
|
||||
|
||||
if ( 0x7f >= car_w ) {
|
||||
hun_y[byt_w++] = car_w;
|
||||
}
|
||||
else if ( 0x7ff >= car_w ) {
|
||||
hun_y[byt_w++] = 0xc0 ^ ((car_w >> 6) & 0x1f);
|
||||
hun_y[byt_w++] = 0x80 ^ (car_w & 0x3f);
|
||||
}
|
||||
else if ( 0xffff >= car_w ) {
|
||||
hun_y[byt_w++] = 0xe0 ^ ((car_w >> 12) & 0xf);
|
||||
hun_y[byt_w++] = 0x80 ^ ((car_w >> 6) & 0x3f);
|
||||
hun_y[byt_w++] = 0x80 ^ (car_w & 0x3f);
|
||||
}
|
||||
else {
|
||||
hun_y[byt_w++] = 0xf0 ^ ((car_w >> 18) & 0x7);
|
||||
hun_y[byt_w++] = 0x80 ^ ((car_w >> 12) & 0x3f);
|
||||
hun_y[byt_w++] = 0x80 ^ ((car_w >> 6) & 0x3f);
|
||||
hun_y[byt_w++] = 0x80 ^ (car_w & 0x3f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c3_free(tat_u->mir.lin_y);
|
||||
tat_u->mir.lin_y = hun_y;
|
||||
tat_u->mir.byt_w = byt_w;
|
||||
tat_u->mir.wor_w = wor_w;
|
||||
tat_u->mir.sap_w = sap_w;
|
||||
|
||||
_term_it_show_line(uty_u, wor_w, sap_w);
|
||||
}
|
||||
|
||||
/* _term_it_show_more(): new current line.
|
||||
*/
|
||||
static void
|
||||
_term_it_show_more(u3_utty* uty_u)
|
||||
{
|
||||
if ( c3y == u3_Host.ops_u.tem ) {
|
||||
_term_it_write_str(uty_u, "\n");
|
||||
} else {
|
||||
_term_it_write_str(uty_u, "\r\n");
|
||||
_term_it_dump(uty_u, TERM_LIT("\n"));
|
||||
}
|
||||
else {
|
||||
_term_it_dump(uty_u, TERM_LIT("\r\n"));
|
||||
}
|
||||
|
||||
uty_u->tat_u.mir.cus_w = 0;
|
||||
}
|
||||
|
||||
@ -658,7 +716,7 @@ _term_io_suck_char(u3_utty* uty_u, c3_y cay_y)
|
||||
if ( c3y == tat_u->esc.bra ) {
|
||||
switch ( cay_y ) {
|
||||
default: {
|
||||
_term_it_write_txt(uty_u, uty_u->ufo_u.out.bel_y);
|
||||
_term_it_dump_buf(uty_u, &uty_u->ufo_u.out.bel_u);
|
||||
break;
|
||||
}
|
||||
case 'A': _term_io_belt(uty_u, u3nc(c3__aro, 'u')); break;
|
||||
@ -687,7 +745,7 @@ _term_io_suck_char(u3_utty* uty_u, c3_y cay_y)
|
||||
else {
|
||||
tat_u->esc.ape = c3n;
|
||||
|
||||
_term_it_write_txt(uty_u, uty_u->ufo_u.out.bel_y);
|
||||
_term_it_dump_buf(uty_u, &uty_u->ufo_u.out.bel_u);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -698,10 +756,9 @@ _term_io_suck_char(u3_utty* uty_u, c3_y cay_y)
|
||||
u3_noun huv = u3i_bytes(tat_u->fut.wid_w, tat_u->fut.syb_y);
|
||||
u3_noun wug;
|
||||
|
||||
// u3l_log("muck-utf8 len %d\n", tat_u->fut.len_w);
|
||||
// u3l_log("muck-utf8 %x\n", huv);
|
||||
// XX implement directly here and jet
|
||||
//
|
||||
wug = u3do("taft", huv);
|
||||
// u3l_log("muck-utf32 %x\n", tat_u->fut.len_w);
|
||||
|
||||
tat_u->fut.len_w = tat_u->fut.wid_w = 0;
|
||||
_term_io_belt(uty_u, u3nt(c3__txt, wug, u3_nul));
|
||||
@ -712,7 +769,7 @@ _term_io_suck_char(u3_utty* uty_u, c3_y cay_y)
|
||||
_term_io_belt(uty_u, u3nt(c3__txt, cay_y, u3_nul));
|
||||
}
|
||||
else if ( 0 == cay_y ) {
|
||||
_term_it_write_txt(uty_u, uty_u->ufo_u.out.bel_y);
|
||||
_term_it_dump_buf(uty_u, &uty_u->ufo_u.out.bel_u);
|
||||
}
|
||||
else if ( 8 == cay_y || 127 == cay_y ) {
|
||||
_term_io_belt(uty_u, u3nc(c3__bac, u3_nul));
|
||||
@ -800,27 +857,104 @@ _term_read_cb(uv_stream_t* tcp_u,
|
||||
c3_free(buf_u->base);
|
||||
}
|
||||
|
||||
/* _term_spin_write_str(): write null-terminated string
|
||||
/* _term_spin_step(): advance spinner state and (re-)render.
|
||||
*/
|
||||
static void
|
||||
_term_spin_write_str(u3_utty* uty_u,
|
||||
const c3_c* str_c)
|
||||
_term_spin_step(u3_utty* uty_u)
|
||||
{
|
||||
// c3_i fid_i = uv_fileno(&uty_u->pop_u);
|
||||
c3_i fid_i = uty_u->pop_u.io_watcher.fd; // XX old libuv
|
||||
c3_w len_w = strlen(str_c);
|
||||
u3_utat* tat_u = &uty_u->tat_u;
|
||||
c3_w bac_w;
|
||||
|
||||
if ( len_w != write(fid_i, str_c, len_w) ) {
|
||||
// ignore, we just tryin
|
||||
// calculate backoff from end of line, or bail out
|
||||
//
|
||||
{
|
||||
c3_w cus_w = tat_u->mir.cus_w;
|
||||
c3_l col_l = tat_u->siz.col_l;
|
||||
|
||||
if ( cus_w >= col_l ) { // shenanigans!
|
||||
return;
|
||||
}
|
||||
|
||||
bac_w = col_l - 1 - cus_w;
|
||||
}
|
||||
}
|
||||
|
||||
/* _term_spin_move_left(): move the cursor left
|
||||
*/
|
||||
static void
|
||||
_term_spin_move_left(u3_utty* uty_u)
|
||||
{
|
||||
_term_spin_write_str(uty_u, (const c3_c*)uty_u->ufo_u.out.cub1_y);
|
||||
c3_d lag_d = tat_u->sun_u.eve_d++;
|
||||
const c3_c daz_c[] = "|/-\\";
|
||||
// | + « + why + » + \0
|
||||
c3_c buf_c[1 + 2 + 4 + 2 + 1];
|
||||
c3_c* cur_c = buf_c;
|
||||
c3_w sol_w = 1; // spinner length (utf-32)
|
||||
|
||||
// set spinner char
|
||||
//
|
||||
*cur_c++ = daz_c[lag_d % (sizeof(daz_c) - 1)];
|
||||
|
||||
// if we have a spinner, add it between brackets
|
||||
//
|
||||
if ( tat_u->sun_u.why_c[0] ) {
|
||||
*cur_c++ = '\xc2';
|
||||
*cur_c++ = '\xab';
|
||||
sol_w++;
|
||||
|
||||
{
|
||||
c3_c* why_c = tat_u->sun_u.why_c;
|
||||
*cur_c++ = *why_c++;
|
||||
*cur_c++ = *why_c++;
|
||||
*cur_c++ = *why_c++;
|
||||
*cur_c++ = *why_c;
|
||||
// XX assumes one glyph per char
|
||||
//
|
||||
sol_w += 4;
|
||||
}
|
||||
|
||||
*cur_c++ = '\xc2';
|
||||
*cur_c++ = '\xbb';
|
||||
sol_w++;
|
||||
}
|
||||
|
||||
*cur_c = '\0';
|
||||
|
||||
// write spinner, adjusting cursor as needed
|
||||
//
|
||||
// NB: we simply bail out if anything goes wrong
|
||||
//
|
||||
{
|
||||
uv_buf_t lef_u = uty_u->ufo_u.out.cub1_u;
|
||||
c3_i fid_i;
|
||||
|
||||
if ( uv_fileno((uv_handle_t*)&uty_u->pop_u, &fid_i) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// One-time cursor backoff.
|
||||
//
|
||||
if ( c3n == tat_u->sun_u.diz_o ) {
|
||||
c3_w i_w;
|
||||
|
||||
for ( i_w = bac_w; i_w < sol_w; i_w++ ) {
|
||||
if ( lef_u.len != write(fid_i, lef_u.base, lef_u.len) ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
tat_u->sun_u.diz_o = c3y;
|
||||
}
|
||||
|
||||
{
|
||||
c3_w len_w = cur_c - buf_c;
|
||||
if ( len_w != write(fid_i, buf_c, len_w) ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Cursor stays on spinner.
|
||||
//
|
||||
while ( sol_w-- ) {
|
||||
if ( lef_u.len != write(fid_i, lef_u.base, lef_u.len) ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* _term_spin_timer_cb(): render spinner
|
||||
@ -829,61 +963,7 @@ static void
|
||||
_term_spin_timer_cb(uv_timer_t* tim_u)
|
||||
{
|
||||
u3_utty* uty_u = tim_u->data;
|
||||
u3_utat* tat_u = &uty_u->tat_u;
|
||||
|
||||
c3_w cus_w = tat_u->mir.cus_w;
|
||||
c3_l col_l = tat_u->siz.col_l;
|
||||
|
||||
if ( cus_w >= col_l ) { // shenanigans!
|
||||
return;
|
||||
}
|
||||
|
||||
c3_w bac_w = col_l - 1 - cus_w; // backoff from end of line
|
||||
c3_d lag_d = tat_u->sun_u.eve_d++;
|
||||
|
||||
const c3_c daz_c[] = "|/-\\";
|
||||
const c3_c dal_c[] = "\xc2\xab";
|
||||
const c3_c dar_c[] = "\xc2\xbb";
|
||||
|
||||
c3_c buf_c[1 + 2 + 4 + 2 + 1];
|
||||
// | + « + why + » + \0
|
||||
|
||||
c3_c* cur_c = buf_c;
|
||||
|
||||
*cur_c++ = daz_c[lag_d % strlen(daz_c)];
|
||||
c3_w sol_w = 1; // spinner length (utf-32)
|
||||
|
||||
if ( tat_u->sun_u.why_c[0] ) {
|
||||
strncpy(cur_c, dal_c, 2);
|
||||
cur_c += 2;
|
||||
sol_w += 1; // length of dal_c (utf-32)
|
||||
|
||||
strncpy(cur_c, tat_u->sun_u.why_c, 4);
|
||||
cur_c += 4;
|
||||
sol_w += 4; // XX assumed utf-8
|
||||
|
||||
strncpy(cur_c, dar_c, 2);
|
||||
cur_c += 2;
|
||||
sol_w += 1; // length of dar_c (utf-32)
|
||||
}
|
||||
|
||||
*cur_c = '\0';
|
||||
|
||||
// One-time cursor backoff.
|
||||
if ( c3n == tat_u->sun_u.diz_o ) {
|
||||
c3_w i_w;
|
||||
for ( i_w = bac_w; i_w < sol_w; i_w++ ) {
|
||||
_term_spin_move_left(uty_u);
|
||||
}
|
||||
}
|
||||
|
||||
_term_spin_write_str(uty_u, buf_c);
|
||||
tat_u->sun_u.diz_o = c3y;
|
||||
|
||||
// Cursor stays on spinner.
|
||||
while ( sol_w-- ) {
|
||||
_term_spin_move_left(uty_u);
|
||||
}
|
||||
_term_spin_step(uty_u);
|
||||
}
|
||||
|
||||
#define _SPIN_COOL_US 500UL // spinner activation delay when cool
|
||||
@ -1081,7 +1161,7 @@ _term_it_put_deco(c3_w* lin_w,
|
||||
*/
|
||||
static void
|
||||
_term_it_show_stub(u3_utty* uty_u,
|
||||
u3_noun tub)
|
||||
u3_noun tub)
|
||||
{
|
||||
c3_w tuc_w = u3qb_lent(tub);
|
||||
|
||||
@ -1198,11 +1278,33 @@ _term_it_show_stub(u3_utty* uty_u,
|
||||
}
|
||||
}
|
||||
|
||||
_term_it_show_line(uty_u, lin_w, i_w, sap_w);
|
||||
_term_it_set_line(uty_u, lin_w, i_w, sap_w);
|
||||
|
||||
u3z(tub);
|
||||
}
|
||||
|
||||
/* _term_it_show_tour(): send utf32 to terminal.
|
||||
*/
|
||||
static void
|
||||
_term_it_show_tour(u3_utty* uty_u,
|
||||
u3_noun lin)
|
||||
{
|
||||
c3_w len_w = u3qb_lent(lin);
|
||||
c3_w* lin_w = c3_malloc( sizeof(c3_w) * len_w );
|
||||
|
||||
{
|
||||
c3_w i_w;
|
||||
|
||||
for ( i_w = 0; u3_nul != lin; i_w++, lin = u3t(lin) ) {
|
||||
lin_w[i_w] = u3r_word(0, u3h(lin));
|
||||
}
|
||||
}
|
||||
|
||||
_term_it_set_line(uty_u, lin_w, len_w, 0);
|
||||
|
||||
u3z(lin);
|
||||
}
|
||||
|
||||
/* _term_ef_blit(): send blit to terminal.
|
||||
*/
|
||||
static void
|
||||
@ -1214,7 +1316,7 @@ _term_ef_blit(u3_utty* uty_u,
|
||||
|
||||
case c3__bel: {
|
||||
if ( c3n == u3_Host.ops_u.tem ) {
|
||||
_term_it_write_txt(uty_u, uty_u->ufo_u.out.bel_y);
|
||||
_term_it_dump_buf(uty_u, &uty_u->ufo_u.out.bel_u);
|
||||
}
|
||||
} break;
|
||||
|
||||
@ -1239,24 +1341,10 @@ _term_ef_blit(u3_utty* uty_u,
|
||||
} break;
|
||||
|
||||
case c3__lin: {
|
||||
u3_noun lin = u3t(blt);
|
||||
c3_w len_w = u3kb_lent(u3k(lin));
|
||||
c3_w* lin_w = c3_malloc( sizeof(c3_w) * len_w );
|
||||
|
||||
{
|
||||
c3_w i_w;
|
||||
|
||||
for ( i_w = 0; u3_nul != lin; i_w++, lin = u3t(lin) ) {
|
||||
lin_w[i_w] = u3r_word(0, u3h(lin));
|
||||
}
|
||||
}
|
||||
|
||||
if ( c3n == u3_Host.ops_u.tem ) {
|
||||
_term_it_show_clear(uty_u);
|
||||
_term_it_show_line(uty_u, lin_w, len_w, 0);
|
||||
} else {
|
||||
_term_it_show_line(uty_u, lin_w, len_w, 0);
|
||||
}
|
||||
_term_it_show_tour(uty_u, u3k(u3t(blt)));
|
||||
} break;
|
||||
|
||||
case c3__mor: {
|
||||
@ -1264,36 +1352,38 @@ _term_ef_blit(u3_utty* uty_u,
|
||||
} break;
|
||||
|
||||
case c3__sav: {
|
||||
_term_it_save(u3k(u3h(u3t(blt))), u3k(u3t(u3t(blt))));
|
||||
u3_noun pax, dat;
|
||||
u3x_cell(u3t(blt), &pax, &dat);
|
||||
|
||||
_term_it_save(u3k(pax), u3k(dat));
|
||||
} break;
|
||||
|
||||
case c3__sag: {
|
||||
u3_noun pib = u3k(u3t(u3t(blt)));
|
||||
u3_noun jam;
|
||||
u3_noun pax, dat;
|
||||
u3x_cell(u3t(blt), &pax, &dat);
|
||||
|
||||
jam = u3ke_jam(pib);
|
||||
|
||||
_term_it_save(u3k(u3h(u3t(blt))), jam);
|
||||
_term_it_save(u3k(pax), u3qe_jam(dat));
|
||||
} break;
|
||||
|
||||
case c3__url: {
|
||||
if ( c3n == u3ud(u3t(blt)) ) {
|
||||
break;
|
||||
} else {
|
||||
c3_c* txt_c = u3r_string(u3t(blt));
|
||||
u3_noun txt = u3t(blt);
|
||||
|
||||
// XX check u3_Host.ops_u.tem ?
|
||||
// XX this looks to be broken,
|
||||
// multiple calls to _show_clear will discard the mirror state
|
||||
//
|
||||
if ( c3y == u3a_is_atom(txt) ) {
|
||||
_term_it_show_clear(uty_u);
|
||||
_term_it_write_str(uty_u, txt_c);
|
||||
c3_free(txt_c);
|
||||
|
||||
_term_it_send_cord(uty_u, u3k(txt));
|
||||
|
||||
_term_it_show_more(uty_u);
|
||||
_term_it_refresh_line(uty_u);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
u3z(blt);
|
||||
|
||||
return;
|
||||
u3z(blt);
|
||||
}
|
||||
|
||||
/* u3_term_io_hija(): hijack console for fprintf, returning FILE*.
|
||||
@ -1329,8 +1419,10 @@ u3_term_io_hija(void)
|
||||
c3_assert(!"hija-fcntl");
|
||||
}
|
||||
_write(uty_u->fid_i, "\r", 1);
|
||||
_write(uty_u->fid_i, uty_u->ufo_u.out.el_y,
|
||||
strlen((c3_c*) uty_u->ufo_u.out.el_y));
|
||||
{
|
||||
uv_buf_t* buf_u = &uty_u->ufo_u.out.el_u;
|
||||
_write(uty_u->fid_i, buf_u->base, buf_u->len);
|
||||
}
|
||||
}
|
||||
return stdout;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user