Something went wrong. Try again.
MIRROR: javascript for 🐜's, a tiny runtime with big ambitions ant.themackabu.dev
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373// TODO: cleanup module, make cleaner
#include <compat.h> // IWYU pragma: keep
#include <stdlib.h>#include <stdio.h>#include <string.h>#include <stdbool.h>#include <ctype.h>#include <uthash.h>#include <uv.h>
#ifdef _WIN32#include <conio.h>#define WIN32_LEAN_AND_MEAN#include <windows.h>#include <io.h>#define STDIN_FILENO 0#define STDOUT_FILENO 1#else#include <termios.h>#include <unistd.h>#include <sys/select.h>#include <sys/ioctl.h>#endif
#include "ant.h"#include "errors.h"#include "runtime.h"#include "internal.h"#include "descriptors.h"#include "tty_ctrl.h"#include "silver/engine.h"
#include "gc/modules.h"#include "modules/events.h"#include "modules/readline.h"#include "modules/process.h"#include "modules/symbol.h"
#define MAX_LINE_LENGTH 4096#define MAX_HISTORY 1000#define DEFAULT_PROMPT "> "#define DEFAULT_HISTORY_SIZE 30#define DEFAULT_TAB_SIZE 8
typedef struct { char **lines; int count; int capacity; int current;} rl_history_t;
typedef struct rl_interface { uint64_t id; ant_value_t input_stream; ant_value_t output_stream; ant_value_t completer; ant_value_t js_obj; char *prompt; char *active_prompt; char *line_buffer; int line_pos; int line_len; rl_history_t history; bool terminal; bool paused; bool closed; bool reading; int history_size; bool remove_history_duplicates; int crlf_delay; int escape_code_timeout; int tab_size; ant_value_t pending_question_resolve; ant_value_t pending_question_reject; uv_tty_t tty_in; uv_tty_t tty_out; bool tty_initialized; int escape_state; char escape_buf[16]; int escape_len; int last_render_rows; UT_hash_handle hh;#ifndef _WIN32 struct termios saved_termios; bool raw_mode; uv_signal_t sigint_watcher; bool sigint_watcher_active;#endif} rl_interface_t;
static uint64_t next_interface_id = 1;static rl_interface_t *interfaces = NULL;static ant_value_t g_rl_async_iter_proto = 0;static ant_value_t g_rl_interface_proto = 0;
static const char *rl_render_prompt(const rl_interface_t *iface) { if (!iface) return ""; return iface->active_prompt ? iface->active_prompt : iface->prompt;}
static void rl_set_active_prompt(rl_interface_t *iface, const char *prompt) { if (!iface) return; free(iface->active_prompt); iface->active_prompt = prompt ? strdup(prompt) : NULL;}
static void rl_clear_active_prompt(rl_interface_t *iface) { if (!iface) return; free(iface->active_prompt); iface->active_prompt = NULL;}
static void rl_history_init(rl_history_t *hist, int capacity) { hist->capacity = capacity > 0 ? capacity : DEFAULT_HISTORY_SIZE; hist->lines = calloc(hist->capacity, sizeof(char*)); hist->count = 0; hist->current = -1;}
static void rl_history_remove_at(rl_history_t *hist, int index) { if (!hist || index < 0 || index >= hist->count) return;
free(hist->lines[index]); if (index < hist->count - 1) memmove( hist->lines + index, hist->lines + index + 1, sizeof(char *) * (size_t)(hist->count - index - 1) ); hist->count--;}
static void rl_history_add(rl_history_t *hist, const char *line, bool remove_duplicates) { int duplicate_index = -1;
if (!line || line[0] == '\0') return; if (!remove_duplicates && hist->count > 0 && strcmp(hist->lines[hist->count - 1], line) == 0) return;
if (remove_duplicates) { for (int i = 0; i < hist->count; i++) { if (strcmp(hist->lines[i], line) != 0) continue; duplicate_index = i; break; }}
if (duplicate_index >= 0) rl_history_remove_at(hist, duplicate_index); if (hist->count >= hist->capacity) rl_history_remove_at(hist, 0);
hist->lines[hist->count++] = strdup(line); hist->current = hist->count;}
static const char *rl_history_prev(rl_history_t *hist) { if (hist->count == 0) return NULL; if (hist->current > 0) hist->current--; return hist->lines[hist->current];}
static const char *rl_history_next(rl_history_t *hist) { if (hist->count == 0) return NULL; if (hist->current < hist->count - 1) { hist->current++; return hist->lines[hist->current]; } hist->current = hist->count; return "";}
static void rl_history_free(rl_history_t *hist) { if (hist->lines) { for (int i = 0; i < hist->count; i++) { free(hist->lines[i]); } free(hist->lines); hist->lines = NULL; } hist->count = 0; hist->current = -1;}
#ifndef _WIN32static void enter_raw_mode(rl_interface_t *iface) { if (iface->raw_mode) return; struct termios raw; if (tcgetattr(STDIN_FILENO, &iface->saved_termios) == -1) return; raw = iface->saved_termios; cfmakeraw(&raw); raw.c_lflag |= ISIG; raw.c_oflag |= OPOST | ONLCR;
if (tcsetattr(STDIN_FILENO, TCSANOW, &raw) == -1) return; iface->raw_mode = true;}
static void exit_raw_mode(rl_interface_t *iface) { if (!iface->raw_mode) return; tcsetattr(STDIN_FILENO, TCSANOW, &iface->saved_termios); iface->raw_mode = false;}#endif
static void write_output(rl_interface_t *iface, const char *str) { fputs(str, stdout); fflush(stdout);}
static int get_terminal_cols(void) { int cols = 80;#ifndef _WIN32 struct winsize ws; if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0 && ws.ws_col > 0) { cols = ws.ws_col; }#else CONSOLE_SCREEN_BUFFER_INFO csbi; if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) { cols = csbi.srWindow.Right - csbi.srWindow.Left + 1; }#endif return cols > 0 ? cols : 80;}
static void move_cursor_to_line_start(rl_interface_t *iface, int cols) { int prompt_len = (int)strlen(rl_render_prompt(iface)); int cursor_cols = prompt_len + iface->line_pos; int cursor_row = cursor_cols / cols; if (cursor_cols > 0 && cursor_cols % cols == 0) cursor_row--;
if (cursor_row > 0) { char move_buf[32]; snprintf(move_buf, sizeof(move_buf), "\033[%dA", cursor_row); write_output(iface, move_buf); } write_output(iface, "\r");}
static void clear_line_display(rl_interface_t *iface) { int cols = get_terminal_cols(); int prompt_len = (int)strlen(rl_render_prompt(iface)); int line_cols = prompt_len + iface->line_len; int current_rows = line_cols > 0 ? (line_cols - 1) / cols + 1 : 1; int rows = iface->last_render_rows > current_rows ? iface->last_render_rows : current_rows;
move_cursor_to_line_start(iface, cols); for (int i = 0; i < rows; i++) { write_output(iface, "\033[K"); if (i < rows - 1) { write_output(iface, "\033[B\r"); } } for (int i = 0; i < rows - 1; i++) { write_output(iface, "\033[A"); } write_output(iface, "\r");}
static void refresh_line(rl_interface_t *iface) { char buf[MAX_LINE_LENGTH + 256]; int cols = get_terminal_cols(); const char *prompt = rl_render_prompt(iface);
clear_line_display(iface); snprintf(buf, sizeof(buf), "%s%s", prompt, iface->line_buffer); write_output(iface, buf);
int prompt_len = (int)strlen(prompt); int end_cols = prompt_len + iface->line_len; int end_row = end_cols > 0 ? end_cols / cols : 0; int cursor_cols = prompt_len + iface->line_pos; int cursor_row = cursor_cols > 0 ? cursor_cols / cols : 0; int cursor_col = cursor_cols > 0 ? cursor_cols % cols : 0; int up_rows = end_row - cursor_row;
if (up_rows > 0) { char move_buf[32]; snprintf(move_buf, sizeof(move_buf), "\033[%dA", up_rows); write_output(iface, move_buf); } write_output(iface, "\r"); if (cursor_col > 0) { char move_buf[32]; snprintf(move_buf, sizeof(move_buf), "\033[%dC", cursor_col); write_output(iface, move_buf); }
iface->last_render_rows = end_cols > 0 ? end_cols / cols + 1 : 1;}
static rl_interface_t *find_interface_by_id(uint64_t id) { rl_interface_t *iface = NULL; HASH_FIND(hh, interfaces, &id, sizeof(uint64_t), iface); return iface;}
static void handle_history_up(rl_interface_t *iface) { const char *hist_line = rl_history_prev(&iface->history); if (hist_line) { strcpy(iface->line_buffer, hist_line); iface->line_len = (int)strlen(iface->line_buffer); iface->line_pos = iface->line_len; refresh_line(iface); }}
static void handle_history_down(rl_interface_t *iface) { const char *hist_line = rl_history_next(&iface->history); if (hist_line) { strcpy(iface->line_buffer, hist_line); iface->line_len = (int)strlen(iface->line_buffer); iface->line_pos = iface->line_len; refresh_line(iface); }}
static void handle_char_input(rl_interface_t *iface, char c) { if (iface->line_len < MAX_LINE_LENGTH - 1) { memmove( iface->line_buffer + iface->line_pos + 1, iface->line_buffer + iface->line_pos, iface->line_len - iface->line_pos + 1 ); iface->line_buffer[iface->line_pos] = c; iface->line_pos++; iface->line_len++; if (iface->line_pos == iface->line_len) { int cols = get_terminal_cols(); int prompt_len = (int)strlen(rl_render_prompt(iface)); int total_cols = prompt_len + iface->line_len; int rows = total_cols > 0 ? total_cols / cols + 1 : 1; if (rows > iface->last_render_rows) iface->last_render_rows = rows; printf("%c", c); fflush(stdout); } else refresh_line(iface); }}
static void handle_backspace(rl_interface_t *iface) { if (iface->line_pos > 0) { if (iface->line_pos == iface->line_len) { iface->line_pos--; iface->line_len--; iface->line_buffer[iface->line_len] = '\0'; write_output(iface, "\b \b"); int cols = get_terminal_cols(); int prompt_len = (int)strlen(rl_render_prompt(iface)); int total_cols = prompt_len + iface->line_len; iface->last_render_rows = total_cols > 0 ? total_cols / cols + 1 : 1; return; }
memmove( iface->line_buffer + iface->line_pos - 1, iface->line_buffer + iface->line_pos, iface->line_len - iface->line_pos + 1 ); iface->line_pos--; iface->line_len--; refresh_line(iface); }}
static void handle_delete(rl_interface_t *iface) { if (iface->line_pos < iface->line_len) { memmove( iface->line_buffer + iface->line_pos, iface->line_buffer + iface->line_pos + 1, iface->line_len - iface->line_pos ); iface->line_len--; refresh_line(iface); }}
static void handle_escape_sequence(rl_interface_t *iface, const char *seq, int len) { if (len >= 2 && seq[0] == '[') { switch (seq[1]) { case 'A': handle_history_up(iface); break; case 'B': handle_history_down(iface); break; case 'C': if (iface->line_pos < iface->line_len) { iface->line_pos++; printf("\033[C"); fflush(stdout); } break; case 'D': if (iface->line_pos > 0) { iface->line_pos--; printf("\033[D"); fflush(stdout); } break; case 'H': iface->line_pos = 0; refresh_line(iface); break; case 'F': iface->line_pos = iface->line_len; refresh_line(iface); break; case '3': if (len >= 3 && seq[2] == '~') { handle_delete(iface); } break; }}}
static void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { buf->base = malloc(suggested_size); buf->len = suggested_size;}
static void emit_event(ant_t *js, rl_interface_t *iface, const char *event_type, ant_value_t *args, int nargs) { if (!iface || vtype(iface->js_obj) == T_UNDEF) return; eventemitter_emit_args(js, iface->js_obj, event_type, args, nargs);}
static ant_value_t get_history_array(ant_t *js, rl_interface_t *iface) { ant_value_t arr = js_mkarr(js); for (int i = 0; i < iface->history.count; i++) js_arr_push( js, arr, js_mkstr(js, iface->history.lines[i], strlen(iface->history.lines[i])) ); return arr;}
static void emit_history_event(ant_t *js, rl_interface_t *iface) { ant_value_t history_arr = get_history_array(js, iface); emit_event(js, iface, "history", &history_arr, 1);}
static void stop_reading(rl_interface_t *iface) { if (!iface->reading) return;
uv_read_stop((uv_stream_t *)&iface->tty_in); iface->reading = false;#ifndef _WIN32 if (iface->sigint_watcher_active) { uv_signal_stop(&iface->sigint_watcher); iface->sigint_watcher_active = false; }#endif}
static bool rl_has_event_listener(ant_t *js, rl_interface_t *iface, const char *event_type) { if (!iface || !event_type || vtype(iface->js_obj) == T_UNDEF) return false; return eventemitter_listener_count(js, iface->js_obj, event_type) > 0;}
static bool rl_add_listener(ant_t *js, rl_interface_t *iface, const char *event_type, ant_value_t listener, bool once) { if (!iface || !event_type || vtype(iface->js_obj) == T_UNDEF) return false; return eventemitter_add_listener(js, iface->js_obj, event_type, listener, once);}
static void rl_remove_listener(ant_t *js, rl_interface_t *iface, const char *event_type, ant_value_t listener) { if (!iface || !event_type || vtype(iface->js_obj) == T_UNDEF) return; eventemitter_remove_listener(js, iface->js_obj, event_type, listener);}
static ant_value_t rl_async_iter_state(ant_t *js, ant_value_t iterator) { ant_value_t state = is_object_type(iterator) ? js_get_slot(iterator, SLOT_DATA) : js_mkundef(); return is_object_type(state) ? state : js_mkundef();}
static ant_value_t rl_async_iter_queue(ant_t *js, ant_value_t state, const char *queue_key) { ant_value_t queue = is_object_type(state) ? js_get(js, state, queue_key) : js_mkundef(); return vtype(queue) == T_ARR ? queue : js_mkundef();}
static ant_offset_t rl_async_iter_queue_head(ant_t *js, ant_value_t state, const char *head_key) { ant_value_t head = is_object_type(state) ? js_get(js, state, head_key) : js_mkundef(); return vtype(head) == T_NUM ? (ant_offset_t)js_getnum(head) : 0;}
static void rl_async_iter_set_queue_head(ant_t *js, ant_value_t state, const char *head_key, ant_offset_t head) { if (is_object_type(state)) js_set(js, state, head_key, js_mknum((double)head));}
static void rl_close_interface(ant_t *js, rl_interface_t *iface) { if (!iface || iface->closed) return; stop_reading(iface);
if (iface->tty_initialized) { uv_close((uv_handle_t *)&iface->tty_in, NULL);#ifndef _WIN32 if (!iface->sigint_watcher_active && uv_is_active((uv_handle_t *)&iface->sigint_watcher)) { uv_close((uv_handle_t *)&iface->sigint_watcher, NULL); } exit_raw_mode(iface);#endif iface->tty_initialized = false; }
iface->closed = true; emit_event(js, iface, "close", NULL, 0);}
static void process_line(ant_t *js, rl_interface_t *iface) { char *line = strdup(iface->line_buffer); rl_history_add(&iface->history, line, iface->remove_history_duplicates); emit_history_event(js, iface); rl_clear_active_prompt(iface); ant_value_t line_val = js_mkstr(js, line, strlen(line)); emit_event(js, iface, "line", &line_val, 1); if (vtype(iface->pending_question_resolve) == T_FUNC) { sv_vm_call(js->vm, js, iface->pending_question_resolve, js_mkundef(), &line_val, 1, NULL, false); iface->pending_question_resolve = js_mkundef(); iface->pending_question_reject = js_mkundef(); } iface->line_buffer[0] = '\0'; iface->line_pos = 0; iface->line_len = 0; free(line);}
static void feed_escape(rl_interface_t *iface, char c) { iface->escape_buf[iface->escape_len++] = c; if (iface->escape_state == 1) { iface->escape_state = (c == '[' || c == 'O') ? 2 : 0; if (!iface->escape_state) iface->escape_len = 0; return; } bool done = (c >= 'A' && c <= 'Z') || c == '~'; if (done) handle_escape_sequence(iface, iface->escape_buf, iface->escape_len); if (done || iface->escape_len >= 15) { iface->escape_state = 0; iface->escape_len = 0; }}
static void process_byte(ant_t *js, rl_interface_t *iface, char c) { if (iface->escape_state > 0) { feed_escape(iface, c); return; } if (c == 27) { iface->escape_state = 1; iface->escape_len = 0; return; }
switch (c) { case '\r': case '\n': putchar('\n'); fflush(stdout); process_line(js, iface); break; case 127: case 8: handle_backspace(iface); break; case 4: if (iface->line_len == 0) rl_close_interface(js, iface); else handle_delete(iface); break; case 1: iface->line_pos = 0; refresh_line(iface); break; case 5: iface->line_pos = iface->line_len; refresh_line(iface); break; case 11: iface->line_buffer[iface->line_pos] = '\0'; iface->line_len = iface->line_pos; refresh_line(iface); break; case 21: iface->line_buffer[0] = '\0'; iface->line_pos = 0; iface->line_len = 0; refresh_line(iface); break; case 12: printf("\033[2J\033[H"); refresh_line(iface); break; default: if (c >= 32 && c < 127) handle_char_input(iface, c); break; }}
static void on_stdin_read(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { rl_interface_t *iface = (rl_interface_t *)stream->data; ant_t *js = rt->js;
if (!iface || iface->closed || iface->paused) goto cleanup;
if (nread < 0) { if (nread == UV_EOF) rl_close_interface(js, iface); goto cleanup; }
for (ssize_t i = 0; i < nread; i++) { process_byte(js, iface, buf->base[i]); if (iface->closed) break; }
if (iface->closed) stop_reading(iface);
cleanup: free(buf->base);}
#ifndef _WIN32static void on_sigint(uv_signal_t *handle, int signum) { rl_interface_t *iface = (rl_interface_t *)handle->data; ant_t *js = rt->js;
if (rl_has_event_listener(js, iface, "SIGINT")) { emit_event(js, iface, "SIGINT", NULL, 0); } else if (process_has_event_listeners("SIGINT")) { ant_value_t sig_arg = js_mkstr(js, "SIGINT", 6); emit_process_event("SIGINT", &sig_arg, 1); } else { uv_signal_stop(handle); raise(SIGINT); }}#endif
static void start_reading(rl_interface_t *iface) { if (iface->reading || iface->closed) return;
if (!iface->tty_initialized) { uv_loop_t *loop = uv_default_loop(); int is_tty = uv_guess_handle(STDIN_FILENO) == UV_TTY;
if (uv_tty_init(loop, &iface->tty_in, STDIN_FILENO, 1) != 0) return;
if (is_tty) {#ifndef _WIN32 enter_raw_mode(iface); uv_signal_init(loop, &iface->sigint_watcher); iface->sigint_watcher.data = iface; uv_signal_start(&iface->sigint_watcher, on_sigint, SIGINT); iface->sigint_watcher_active = true;#endif }
iface->tty_in.data = iface; iface->tty_initialized = true; }
iface->reading = true; uv_read_start((uv_stream_t *)&iface->tty_in, alloc_buffer, on_stdin_read);}
static rl_interface_t *get_interface(ant_t *js, ant_value_t this_obj) { ant_value_t id_val = js_get(js, this_obj, "_rl_id"); if (vtype(id_val) != T_NUM) return NULL; uint64_t id = (uint64_t)js_getnum(id_val); rl_interface_t *iface = NULL; HASH_FIND(hh, interfaces, &id, sizeof(uint64_t), iface); return iface;}
static ant_value_t rl_interface_close(ant_t *js, ant_value_t *args, int nargs) { ant_value_t this_obj = js_getthis(js); rl_interface_t *iface = get_interface(js, this_obj); if (!iface || iface->closed) return js_mkundef(); rl_close_interface(js, iface); return js_mkundef();}
static ant_value_t rl_interface_pause(ant_t *js, ant_value_t *args, int nargs) { ant_value_t this_obj = js_getthis(js); rl_interface_t *iface = get_interface(js, this_obj); if (!iface) return js_mkerr(js, "Invalid Interface"); if (!iface->paused) { iface->paused = true; stop_reading(iface); emit_event(js, iface, "pause", NULL, 0); } return this_obj;}
static ant_value_t rl_interface_resume(ant_t *js, ant_value_t *args, int nargs) { ant_value_t this_obj = js_getthis(js); rl_interface_t *iface = get_interface(js, this_obj); if (!iface) return js_mkerr(js, "Invalid Interface"); if (iface->paused) { iface->paused = false; start_reading(iface); emit_event(js, iface, "resume", NULL, 0); } return this_obj;}
static ant_value_t rl_interface_prompt(ant_t *js, ant_value_t *args, int nargs) { ant_value_t this_obj = js_getthis(js); rl_interface_t *iface = get_interface(js, this_obj); if (!iface || iface->closed) return js_mkundef(); if (iface->paused) { iface->paused = false; emit_event(js, iface, "resume", NULL, 0); } bool preserve_cursor = false; if (nargs > 0) preserve_cursor = js_truthy(js, args[0]); if (!preserve_cursor) { iface->line_buffer[0] = '\0'; iface->line_pos = 0; iface->line_len = 0; } write_output(iface, rl_render_prompt(iface)); if (iface->line_len > 0) { write_output(iface, iface->line_buffer); } start_reading(iface); return js_mkundef();}
static ant_value_t rl_interface_set_prompt(ant_t *js, ant_value_t *args, int nargs) { ant_value_t this_obj = js_getthis(js); rl_interface_t *iface = get_interface(js, this_obj); if (!iface) return js_mkerr(js, "Invalid Interface"); if (nargs < 1) return js_mkundef(); char *new_prompt = js_getstr(js, args[0], NULL); if (new_prompt) { free(iface->prompt); iface->prompt = strdup(new_prompt); } return js_mkundef();}
static ant_value_t rl_interface_get_prompt(ant_t *js, ant_value_t *args, int nargs) { ant_value_t this_obj = js_getthis(js); rl_interface_t *iface = get_interface(js, this_obj); if (!iface) return js_mkerr(js, "Invalid Interface"); return js_mkstr(js, iface->prompt, strlen(iface->prompt));}
static void process_key_sequence(rl_interface_t *iface, const char *name, bool ctrl, bool meta, bool shift) { (void)meta; (void)shift; if (!name) return; if (strcmp(name, "return") == 0 || strcmp(name, "enter") == 0) { printf("\n"); fflush(stdout); } else if (strcmp(name, "backspace") == 0) { if (iface->line_pos > 0) { memmove(iface->line_buffer + iface->line_pos - 1, iface->line_buffer + iface->line_pos, iface->line_len - iface->line_pos + 1); iface->line_pos--; iface->line_len--; } } else if (strcmp(name, "delete") == 0) { if (iface->line_pos < iface->line_len) { memmove(iface->line_buffer + iface->line_pos, iface->line_buffer + iface->line_pos + 1, iface->line_len - iface->line_pos); iface->line_len--; } } else if (strcmp(name, "left") == 0) { if (iface->line_pos > 0) iface->line_pos--; } else if (strcmp(name, "right") == 0) { if (iface->line_pos < iface->line_len) iface->line_pos++; } else if (strcmp(name, "home") == 0 || (ctrl && strcmp(name, "a") == 0)) { iface->line_pos = 0; } else if (strcmp(name, "end") == 0 || (ctrl && strcmp(name, "e") == 0)) { iface->line_pos = iface->line_len; } else if (ctrl && strcmp(name, "u") == 0) { iface->line_buffer[0] = '\0'; iface->line_pos = 0; iface->line_len = 0; } else if (ctrl && strcmp(name, "k") == 0) { iface->line_buffer[iface->line_pos] = '\0'; iface->line_len = iface->line_pos; }}
static ant_value_t rl_interface_write(ant_t *js, ant_value_t *args, int nargs) { ant_value_t this_obj = js_getthis(js); rl_interface_t *iface = get_interface(js, this_obj); if (!iface || iface->closed) return js_mkundef(); if (iface->paused) { iface->paused = false; emit_event(js, iface, "resume", NULL, 0); } if (nargs >= 2 && is_special_object(args[1])) { ant_value_t key = args[1]; ant_value_t name_val = js_get(js, key, "name"); ant_value_t ctrl_val = js_get(js, key, "ctrl"); ant_value_t meta_val = js_get(js, key, "meta"); ant_value_t shift_val = js_get(js, key, "shift"); char *name = (vtype(name_val) == T_STR) ? js_getstr(js, name_val, NULL) : NULL; bool ctrl = js_truthy(js, ctrl_val); bool meta = js_truthy(js, meta_val); bool shift = js_truthy(js, shift_val); if (name) { process_key_sequence(iface, name, ctrl, meta, shift); return js_mkundef(); } } if (nargs < 1 || vtype(args[0]) == T_NULL || vtype(args[0]) == T_UNDEF) { return js_mkundef(); } size_t len; char *data = js_getstr(js, args[0], &len); if (!data) return js_mkundef(); for (size_t i = 0; i < len && iface->line_len < MAX_LINE_LENGTH - 1; i++) { char c = data[i]; if (c == '\n' || c == '\r') { process_line(js, iface); } else { memmove(iface->line_buffer + iface->line_pos + 1, iface->line_buffer + iface->line_pos, iface->line_len - iface->line_pos + 1); iface->line_buffer[iface->line_pos] = c; iface->line_pos++; iface->line_len++; } } return js_mkundef();}
static ant_value_t rl_interface_line_getter(ant_t *js, ant_value_t *args, int nargs) { ant_value_t this_obj = js_getthis(js); rl_interface_t *iface = get_interface(js, this_obj); if (!iface) return js_mkundef(); return js_mkstr(js, iface->line_buffer, strlen(iface->line_buffer));}
static ant_value_t rl_interface_cursor_getter(ant_t *js, ant_value_t *args, int nargs) { ant_value_t this_obj = js_getthis(js); rl_interface_t *iface = get_interface(js, this_obj); if (!iface) return js_mknum(0); return js_mknum((double)iface->line_pos);}
static ant_value_t rl_interface_question_callback(ant_t *js, ant_value_t *args, int nargs) { ant_value_t this_obj = js_getthis(js); rl_interface_t *iface = get_interface(js, this_obj); if (!iface || iface->closed) return js_mkundef(); if (nargs < 2) return js_mkerr(js, "question requires query and callback"); size_t query_len; char *query = js_getstr(js, args[0], &query_len); if (!query) return js_mkerr(js, "query must be a string"); int t = vtype(args[1]); if (t != T_FUNC && t != T_CFUNC) { return js_mkerr(js, "callback must be a function"); } rl_set_active_prompt(iface, query); write_output(iface, rl_render_prompt(iface)); if (!rl_add_listener(js, iface, "line", args[1], true)) return js_mkerr(js, "listener must be a function"); return js_mkundef();}
static ant_value_t rl_interface_question_promise(ant_t *js, ant_value_t *args, int nargs) { ant_value_t this_obj = js_getthis(js); rl_interface_t *iface = get_interface(js, this_obj); if (!iface || iface->closed) return js_mkerr(js, "Interface is closed"); if (nargs < 1) return js_mkerr(js, "question requires a query string"); size_t query_len; char *query = js_getstr(js, args[0], &query_len); if (!query) return js_mkerr(js, "query must be a string"); ant_value_t promise = js_mkpromise(js); rl_set_active_prompt(iface, query); write_output(iface, rl_render_prompt(iface)); iface->pending_question_resolve = js_get(js, promise, "_resolve"); iface->pending_question_reject = js_get(js, promise, "_reject"); return promise;}
static ant_value_t rl_interface_get_cursor_pos(ant_t *js, ant_value_t *args, int nargs) { ant_value_t this_obj = js_getthis(js); rl_interface_t *iface = get_interface(js, this_obj); if (!iface) { ant_value_t result = js_mkobj(js); js_set(js, result, "rows", js_mknum(0)); js_set(js, result, "cols", js_mknum(0)); return result; } int prompt_len = (int)strlen(rl_render_prompt(iface)); int total_cols = prompt_len + iface->line_pos; int cols = 80;#ifndef _WIN32 struct winsize ws; if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0 && ws.ws_col > 0) { cols = ws.ws_col; }#else CONSOLE_SCREEN_BUFFER_INFO csbi; if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) { cols = csbi.srWindow.Right - csbi.srWindow.Left + 1; }#endif int rows = total_cols / cols; int col_pos = total_cols % cols; ant_value_t result = js_mkobj(js); js_set(js, result, "rows", js_mknum((double)rows)); js_set(js, result, "cols", js_mknum((double)col_pos)); return result;}
static ant_value_t rl_interface_closed_getter(ant_t *js, ant_value_t *args, int nargs) { ant_value_t this_obj = js_getthis(js); rl_interface_t *iface = get_interface(js, this_obj); if (!iface) return js_true; return js_bool(iface->closed);}
static void free_interface(rl_interface_t *iface) { if (!iface) return; HASH_DEL(interfaces, iface); free(iface->prompt); free(iface->active_prompt); free(iface->line_buffer); rl_history_free(&iface->history); free(iface);}
static ant_value_t rl_clear_line(ant_t *js, ant_value_t *args, int nargs) { int dir = 0; if (!tty_ctrl_parse_clear_line_dir(args, nargs, 1, &dir)) return js_false;
size_t seq_len = 0; const char *seq = tty_ctrl_clear_line_seq(dir, &seq_len); return tty_ctrl_bool_result(js, tty_ctrl_write_stream(stdout, seq, seq_len, true));}
static ant_value_t rl_clear_screen_down(ant_t *js, ant_value_t *args, int nargs) { size_t seq_len = 0; const char *seq = tty_ctrl_clear_screen_down_seq(&seq_len); return tty_ctrl_bool_result(js, tty_ctrl_write_stream(stdout, seq, seq_len, true));}
static ant_value_t rl_cursor_to(ant_t *js, ant_value_t *args, int nargs) { tty_ctrl_cursor_to_args_t parsed; if (!tty_ctrl_parse_cursor_to_args(args, nargs, 1, 2, &parsed)) return js_false;
char seq[64]; size_t seq_len = 0; bool ok = tty_ctrl_build_cursor_to( seq, sizeof(seq), parsed.x, parsed.has_y, parsed.y, &seq_len ); if (!ok) return js_false;
return tty_ctrl_bool_result(js, tty_ctrl_write_stream(stdout, seq, seq_len, true));}
static ant_value_t rl_move_cursor(ant_t *js, ant_value_t *args, int nargs) { int dx = 0; int dy = 0; if (!tty_ctrl_parse_move_cursor_args(args, nargs, 1, 2, &dx, &dy)) return js_false;
bool ok = true; if (dx != 0) { char seq_x[32]; size_t len_x = 0; ok = tty_ctrl_build_move_cursor_axis(seq_x, sizeof(seq_x), dx, true, &len_x); if (ok) ok = tty_ctrl_write_stream(stdout, seq_x, len_x, false); }
if (ok && dy != 0) { char seq_y[32]; size_t len_y = 0; ok = tty_ctrl_build_move_cursor_axis(seq_y, sizeof(seq_y), dy, false, &len_y); if (ok) ok = tty_ctrl_write_stream(stdout, seq_y, len_y, false); }
if (!ok) return js_false; return tty_ctrl_bool_result(js, fflush(stdout) == 0);}
static ant_value_t rl_emit_keypress_events(ant_t *js, ant_value_t *args, int nargs) { if (nargs > 0) { ant_value_t stdin_obj = js_get(js, js_get(js, js_glob(js), "process"), "stdin"); if (stdin_obj != args[0]) { return js_mkerr(js, "emitKeypressEvents only supports process.stdin"); } } process_enable_keypress_events(); return js_mkundef();}
bool has_active_readline_interfaces(void) { rl_interface_t *iface, *tmp; HASH_ITER(hh, interfaces, iface, tmp) { if (!iface->closed && iface->reading) return true; } return false;}
static void rl_async_iter_compact_queue(ant_t *js, ant_value_t state, const char *queue_key, const char *head_key) { ant_value_t queue = rl_async_iter_queue(js, state, queue_key); ant_offset_t head = rl_async_iter_queue_head(js, state, head_key); ant_offset_t len = vtype(queue) == T_ARR ? js_arr_len(js, queue) : 0; ant_value_t compact = 0;
if (vtype(queue) != T_ARR || head == 0) return;
if (head >= len) { js_set(js, state, queue_key, js_mkarr(js)); js_set(js, state, head_key, js_mknum(0)); return; }
if (head <= 32 && head * 2 < len) return;
compact = js_mkarr(js); for (ant_offset_t i = head; i < len; i++) js_arr_push(js, compact, js_arr_get(js, queue, i)); js_set(js, state, queue_key, compact); js_set(js, state, head_key, js_mknum(0));}
static void rl_async_iter_queue_push(ant_t *js, ant_value_t state, const char *queue_key, ant_value_t value) { ant_value_t queue = rl_async_iter_queue(js, state, queue_key); if (vtype(queue) == T_ARR) js_arr_push(js, queue, value);}
static ant_value_t rl_async_iter_queue_shift(ant_t *js, ant_value_t state, const char *queue_key, const char *head_key) { ant_value_t queue = rl_async_iter_queue(js, state, queue_key); ant_offset_t head = rl_async_iter_queue_head(js, state, head_key); ant_offset_t len = vtype(queue) == T_ARR ? js_arr_len(js, queue) : 0; ant_value_t value = js_mkundef();
if (vtype(queue) != T_ARR || head >= len) return js_mkundef(); value = js_arr_get(js, queue, head); rl_async_iter_set_queue_head(js, state, head_key, head + 1); rl_async_iter_compact_queue(js, state, queue_key, head_key); return value;}
static void rl_async_iter_cleanup(ant_t *js, ant_value_t state) { ant_value_t iface_obj = is_object_type(state) ? js_get(js, state, "iface") : js_mkundef(); rl_interface_t *iface = get_interface(js, iface_obj); if (!iface) return;
rl_remove_listener(js, iface, "line", js_get(js, state, "onLine")); rl_remove_listener(js, iface, "close", js_get(js, state, "onClose"));}
static void rl_async_iter_finish(ant_t *js, ant_value_t state) { if (!is_object_type(state)) return;
js_set(js, state, "done", js_true); rl_async_iter_cleanup(js, state);
for (;;) { ant_value_t pending = rl_async_iter_queue_shift(js, state, "pending", "pendingHead"); if (vtype(pending) != T_PROMISE) break; js_resolve_promise(js, pending, js_iter_result(js, false, js_mkundef())); }}
static ant_value_t rl_async_iter_on_line(ant_t *js, ant_value_t *args, int nargs) { ant_value_t state = rl_async_iter_state(js, js_getcurrentfunc(js)); ant_value_t line = nargs > 0 ? args[0] : js_mkundef(); ant_value_t pending = 0;
if (!is_object_type(state)) return js_mkundef(); if (js_truthy(js, js_get(js, state, "done"))) return js_mkundef();
pending = rl_async_iter_queue_shift(js, state, "pending", "pendingHead"); if (vtype(pending) == T_PROMISE) { js_resolve_promise(js, pending, js_iter_result(js, true, line)); } else rl_async_iter_queue_push(js, state, "buffer", line);
return js_mkundef();}
static ant_value_t rl_async_iter_on_close(ant_t *js, ant_value_t *args, int nargs) { ant_value_t state = rl_async_iter_state(js, js_getcurrentfunc(js)); rl_async_iter_finish(js, state); return js_mkundef();}
static ant_value_t rl_async_iter_next(ant_t *js, ant_value_t *args, int nargs) { ant_value_t state = rl_async_iter_state(js, js_getthis(js)); ant_value_t promise = js_mkpromise(js); ant_value_t value = 0;
if (!is_object_type(state)) { js_resolve_promise(js, promise, js_iter_result(js, false, js_mkundef())); return promise; }
value = rl_async_iter_queue_shift(js, state, "buffer", "bufferHead"); if (vtype(value) != T_UNDEF) { js_resolve_promise(js, promise, js_iter_result(js, true, value)); return promise; }
if (js_truthy(js, js_get(js, state, "done"))) { js_resolve_promise(js, promise, js_iter_result(js, false, js_mkundef())); return promise; }
rl_async_iter_queue_push(js, state, "pending", promise); return promise;}
static ant_value_t rl_async_iter_return(ant_t *js, ant_value_t *args, int nargs) { ant_value_t state = rl_async_iter_state(js, js_getthis(js)); ant_value_t promise = js_mkpromise(js);
if (!is_object_type(state)) { js_resolve_promise(js, promise, js_iter_result(js, false, js_mkundef())); return promise; }
if (!js_truthy(js, js_get(js, state, "done"))) { ant_value_t iface_obj = js_get(js, state, "iface"); rl_interface_t *iface = get_interface(js, iface_obj); if (iface && !iface->closed) { ant_value_t old_this = js_getthis(js); js_setthis(js, iface_obj); rl_interface_close(js, NULL, 0); js_setthis(js, old_this); } else rl_async_iter_finish(js, state); }
js_resolve_promise(js, promise, js_iter_result(js, false, js_mkundef())); return promise;}
static ant_value_t rl_get_async_iter_proto(ant_t *js) { if (is_object_type(g_rl_async_iter_proto)) return g_rl_async_iter_proto;
g_rl_async_iter_proto = js_mkobj(js); js_set(js, g_rl_async_iter_proto, "next", js_mkfun(rl_async_iter_next)); js_set(js, g_rl_async_iter_proto, "return", js_mkfun(rl_async_iter_return)); js_set_sym(js, g_rl_async_iter_proto, get_asyncIterator_sym(), js_mkfun(sym_this_cb)); js_set_sym(js, g_rl_async_iter_proto, get_toStringTag_sym(), js_mkstr(js, "AsyncIterator", 13));
return g_rl_async_iter_proto;}
static ant_value_t rl_interface_async_iterator(ant_t *js, ant_value_t *args, int nargs) { ant_value_t this_obj = js_getthis(js); rl_interface_t *iface = get_interface(js, this_obj); ant_value_t iterator = 0; ant_value_t state = 0; ant_value_t on_line = 0; ant_value_t on_close = 0; if (!iface) return js_mkerr(js, "Invalid Interface");
iterator = js_mkobj(js); state = js_mkobj(js);
js_set_proto_init(iterator, rl_get_async_iter_proto(js)); js_set_slot_wb(js, iterator, SLOT_DATA, state);
js_set(js, state, "iface", this_obj); js_set(js, state, "buffer", js_mkarr(js)); js_set(js, state, "bufferHead", js_mknum(0)); js_set(js, state, "pending", js_mkarr(js)); js_set(js, state, "pendingHead", js_mknum(0)); js_set(js, state, "done", js_bool(iface->closed));
if (!iface->closed) { on_line = js_heavy_mkfun(js, rl_async_iter_on_line, state); on_close = js_heavy_mkfun(js, rl_async_iter_on_close, state); js_set(js, state, "onLine", on_line); js_set(js, state, "onClose", on_close); if (!rl_add_listener(js, iface, "line", on_line, false) || !rl_add_listener(js, iface, "close", on_close, false)) { rl_remove_listener(js, iface, "line", on_line); rl_remove_listener(js, iface, "close", on_close); return js_mkerr(js, "listener must be a function"); }}
return iterator;}
static ant_value_t rl_get_interface_proto(ant_t *js) { if (is_object_type(g_rl_interface_proto)) return g_rl_interface_proto;
g_rl_interface_proto = js_mkobj(js); js_set_proto_init(g_rl_interface_proto, eventemitter_prototype(js));
js_set(js, g_rl_interface_proto, "close", js_mkfun(rl_interface_close)); js_set(js, g_rl_interface_proto, "pause", js_mkfun(rl_interface_pause)); js_set(js, g_rl_interface_proto, "resume", js_mkfun(rl_interface_resume)); js_set(js, g_rl_interface_proto, "prompt", js_mkfun(rl_interface_prompt)); js_set(js, g_rl_interface_proto, "setPrompt", js_mkfun(rl_interface_set_prompt)); js_set(js, g_rl_interface_proto, "getPrompt", js_mkfun(rl_interface_get_prompt)); js_set(js, g_rl_interface_proto, "write", js_mkfun(rl_interface_write)); js_set(js, g_rl_interface_proto, "question", js_mkfun(rl_interface_question_callback)); js_set(js, g_rl_interface_proto, "getCursorPos", js_mkfun(rl_interface_get_cursor_pos));
js_set_getter_desc(js, g_rl_interface_proto, "line", 4, js_mkfun(rl_interface_line_getter), JS_DESC_E | JS_DESC_C); js_set_getter_desc(js, g_rl_interface_proto, "cursor", 6, js_mkfun(rl_interface_cursor_getter), JS_DESC_E | JS_DESC_C); js_set_getter_desc(js, g_rl_interface_proto, "closed", 6, js_mkfun(rl_interface_closed_getter), JS_DESC_E | JS_DESC_C); js_set_sym(js, g_rl_interface_proto, get_asyncIterator_sym(), js_mkfun(rl_interface_async_iterator)); js_set_sym(js, g_rl_interface_proto, get_toStringTag_sym(), js_mkstr(js, "Interface", 9));
return g_rl_interface_proto;}
static ant_value_t rl_create_interface(ant_t *js, ant_value_t *args, int nargs) { if (nargs < 1) return js_mkerr(js, "createInterface requires options"); ant_value_t options = args[0]; if (!is_special_object(options)) return js_mkerr(js, "options must be an object"); rl_interface_t *iface = calloc(1, sizeof(rl_interface_t)); if (!iface) return js_mkerr(js, "out of memory"); iface->id = next_interface_id++; iface->prompt = strdup(DEFAULT_PROMPT); iface->active_prompt = NULL; iface->line_buffer = calloc(MAX_LINE_LENGTH, 1); iface->line_pos = 0; iface->line_len = 0; iface->paused = false; iface->closed = false; iface->reading = false; iface->pending_question_resolve = js_mkundef(); iface->pending_question_reject = js_mkundef(); iface->tty_initialized = false; iface->escape_state = 0; iface->escape_len = 0; iface->last_render_rows = 1; iface->js_obj = js_mkundef();#ifndef _WIN32 iface->raw_mode = false;#endif iface->input_stream = js_get(js, options, "input"); iface->output_stream = js_get(js, options, "output"); ant_value_t terminal_val = js_get(js, options, "terminal"); iface->terminal = terminal_val == js_true || vtype(terminal_val) == T_UNDEF; ant_value_t history_size_val = js_get(js, options, "historySize"); iface->history_size = (vtype(history_size_val) == T_NUM) ? (int)js_getnum(history_size_val) : DEFAULT_HISTORY_SIZE; ant_value_t remove_dup_val = js_get(js, options, "removeHistoryDuplicates"); iface->remove_history_duplicates = js_truthy(js, remove_dup_val); ant_value_t prompt_val = js_get(js, options, "prompt"); if (vtype(prompt_val) == T_STR) { free(iface->prompt); iface->prompt = strdup(js_getstr(js, prompt_val, NULL)); } ant_value_t crlf_delay_val = js_get(js, options, "crlfDelay"); iface->crlf_delay = (vtype(crlf_delay_val) == T_NUM) ? (int)js_getnum(crlf_delay_val) : 100; if (iface->crlf_delay < 100) iface->crlf_delay = 100; ant_value_t tab_size_val = js_get(js, options, "tabSize"); iface->tab_size = (vtype(tab_size_val) == T_NUM) ? (int)js_getnum(tab_size_val) : DEFAULT_TAB_SIZE; if (iface->tab_size < 1) iface->tab_size = 1; ant_value_t completer_val = js_get(js, options, "completer"); int ctype = vtype(completer_val); iface->completer = (ctype == T_FUNC || ctype == T_CFUNC) ? completer_val : js_mkundef(); ant_value_t history_val = js_get(js, options, "history"); if (is_special_object(history_val)) { ant_value_t len_val = js_get(js, history_val, "length"); int len = (vtype(len_val) == T_NUM) ? (int)js_getnum(len_val) : 0; rl_history_init(&iface->history, iface->history_size); for (int i = 0; i < len; i++) { char key[16]; snprintf(key, sizeof(key), "%d", i); ant_value_t item = js_get(js, history_val, key); if (vtype(item) == T_STR) { char *line = js_getstr(js, item, NULL); if (line) rl_history_add(&iface->history, line, false); } } } else rl_history_init(&iface->history, iface->history_size); HASH_ADD(hh, interfaces, id, sizeof(uint64_t), iface); ant_value_t obj = js_mkobj(js); js_set_proto_init(obj, rl_get_interface_proto(js)); iface->js_obj = obj; js_set(js, obj, "_rl_id", js_mknum((double)iface->id)); js_set(js, obj, "terminal", js_bool(iface->terminal));
start_reading(iface); return obj;}
static ant_value_t rl_create_interface_promises(ant_t *js, ant_value_t *args, int nargs) { ant_value_t iface_obj = rl_create_interface(js, args, nargs); if (vtype(iface_obj) == T_ERR) return iface_obj; js_set(js, iface_obj, "question", js_mkfun(rl_interface_question_promise)); return iface_obj;}
ant_value_t readline_library(ant_t *js) { ant_value_t lib = js_mkobj(js);
js_set(js, lib, "createInterface", js_mkfun(rl_create_interface)); js_set(js, lib, "clearLine", js_mkfun(rl_clear_line)); js_set(js, lib, "clearScreenDown", js_mkfun(rl_clear_screen_down)); js_set(js, lib, "cursorTo", js_mkfun(rl_cursor_to)); js_set(js, lib, "moveCursor", js_mkfun(rl_move_cursor)); js_set(js, lib, "emitKeypressEvents", js_mkfun(rl_emit_keypress_events)); js_set_sym(js, lib, get_toStringTag_sym(), js_mkstr(js, "readline", 8)); return lib;}
ant_value_t readline_promises_library(ant_t *js) { ant_value_t lib = js_mkobj(js);
js_set(js, lib, "createInterface", js_mkfun(rl_create_interface_promises)); js_set(js, lib, "clearLine", js_mkfun(rl_clear_line)); js_set(js, lib, "clearScreenDown", js_mkfun(rl_clear_screen_down)); js_set(js, lib, "cursorTo", js_mkfun(rl_cursor_to)); js_set(js, lib, "moveCursor", js_mkfun(rl_move_cursor)); js_set(js, lib, "emitKeypressEvents", js_mkfun(rl_emit_keypress_events)); js_set_sym(js, lib, get_toStringTag_sym(), js_mkstr(js, "readline/promises", 17)); return lib;}
void gc_mark_readline(ant_t *js, gc_mark_fn mark) { if (g_rl_async_iter_proto) mark(js, g_rl_async_iter_proto); if (g_rl_interface_proto) mark(js, g_rl_interface_proto); rl_interface_t *iface, *tmp; HASH_ITER(hh, interfaces, iface, tmp) { mark(js, iface->input_stream); mark(js, iface->output_stream); mark(js, iface->completer); mark(js, iface->js_obj); mark(js, iface->pending_question_resolve); mark(js, iface->pending_question_reject); }}