Something went wrong. Try again.
javascript for 🐜's, a tiny runtime with big ambitions antjs.org
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438// 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 <math.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 "cfunc.h"#include "errors.h"#include "internal.h"#include "descriptors.h"#include "silver/call.h"#include "tty_ctrl.h"
#include "gc/modules.h"#include "modules/events.h"#include "modules/readline.h"#include "modules/process.h"#include "modules/symbol.h"#include "modules/iterator.h"
#define MAX_LINE_LENGTH 4096#define MAX_HISTORY 1000#define DEFAULT_PROMPT "> "#define DEFAULT_HISTORY_SIZE 30#define DEFAULT_TAB_SIZE 8#define MAX_SAFE_ARRAY_LENGTH 9007199254740991ULL
typedef struct { char **lines; int count; int capacity; int current;} rl_history_t;
struct rl_interface_s { ant_t *js; 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 should_echo; 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_promise; 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; bool sigint_watcher_initialized;#endif};
static const char *rl_render_prompt(const rl_interface_t *iface) { if (!iface) return ""; return iface->active_prompt ? iface->active_prompt : iface->prompt;}
static int rl_normalize_history_capacity(int capacity) { if (capacity <= 0) return DEFAULT_HISTORY_SIZE; return capacity > MAX_HISTORY ? MAX_HISTORY : capacity;}
static int rl_history_capacity_from_value(ant_value_t value) { if (vtype(value) != kTypeNumber) return DEFAULT_HISTORY_SIZE;
double n = js_getnum(value); if (!isfinite(n) || n <= 0) return DEFAULT_HISTORY_SIZE; if (n > MAX_HISTORY) return MAX_HISTORY; return (int)n;}
static unsigned long long rl_history_length_from_value(ant_value_t value) { if (vtype(value) != kTypeNumber) return 0;
double n = js_getnum(value); if (!isfinite(n) || n <= 0) return 0; if (n > (double)MAX_SAFE_ARRAY_LENGTH) return MAX_SAFE_ARRAY_LENGTH; return (unsigned long long)n;}
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 = rl_normalize_history_capacity(capacity); hist->lines = calloc((size_t)hist->capacity, sizeof(char*)); if (!hist->lines) hist->capacity = 0; 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 (!hist || !hist->lines || hist->capacity <= 0) return; 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);
char *copy = strdup(line); if (!copy) return;
hist->lines[hist->count++] = copy; 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 "";}
#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) { if (!iface->should_echo) return; 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 void set_line_buffer(rl_interface_t *iface, const char *line) { if (!iface || !iface->line_buffer || !line) return;
size_t len = strlen(line); if (len >= MAX_LINE_LENGTH) len = MAX_LINE_LENGTH - 1;
memcpy(iface->line_buffer, line, len); iface->line_buffer[len] = '\0'; iface->line_len = (int)len; iface->line_pos = iface->line_len;}
static void handle_history_up(rl_interface_t *iface) { const char *hist_line = rl_history_prev(&iface->history); if (hist_line) { set_line_buffer(iface, hist_line); refresh_line(iface); }}
static void handle_history_down(rl_interface_t *iface) { const char *hist_line = rl_history_next(&iface->history); if (hist_line) { set_line_buffer(iface, hist_line); 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; if (iface->should_echo) { 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++; if (iface->should_echo) { printf("\033[C"); fflush(stdout); } } break; case 'D': if (iface->line_pos > 0) { iface->line_pos--; if (iface->should_echo) { 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 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) == kTypeUndefined) 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;
iface->reading = false;#ifndef _WIN32 if (iface->sigint_watcher_active) { uv_signal_stop(&iface->sigint_watcher); iface->sigint_watcher_active = false; }#endif if (!has_active_readline_interfaces(iface->js)) process_stdin_detach_reader(iface->js);}
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) == kTypeUndefined) 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) == kTypeUndefined) 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) == kTypeUndefined) 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) == kTypeArray ? 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) == kTypeNumber ? (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);
#ifndef _WIN32 exit_raw_mode(iface);#endif 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_promise) == kTypePromise) { js_resolve_promise(js, iface->pending_question_promise, line_val); iface->pending_question_promise = 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': if (iface->should_echo) { 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: if (iface->should_echo) printf("\033[2J\033[H"); refresh_line(iface); break; default: if (c >= 32 && c < 127) handle_char_input(iface, c); break; }}
static void rl_feed_stdin_bytes(ant_t *js, const char *buf, size_t len) { rl_interface_t *iface, *tmp; HASH_ITER(hh, js->rl_interfaces, iface, tmp) { if (iface->closed || !iface->reading || iface->paused) continue; for (size_t i = 0; i < len; i++) { process_byte(js, iface, buf[i]); if (iface->closed) break; } }}
static void rl_handle_stdin_eof(ant_t *js) { rl_interface_t *iface, *tmp; HASH_ITER(hh, js->rl_interfaces, iface, tmp) if (!iface->closed && iface->reading) rl_close_interface(js, iface);}
#ifndef _WIN32static void on_sigint(uv_signal_t *handle, int signum) { rl_interface_t *iface = (rl_interface_t *)handle->data; ant_t *js = iface->js;
if (rl_has_event_listener(js, iface, "SIGINT")) { emit_event(js, iface, "SIGINT", NULL, 0); } else if (process_has_event_listeners(js, "SIGINT")) { ant_value_t sig_arg = js_mkstr(js, "SIGINT", 6); emit_process_event(js, "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; int is_tty = uv_guess_handle(STDIN_FILENO) == UV_TTY;
#ifndef _WIN32 if (is_tty && iface->should_echo) { enter_raw_mode(iface); if (!iface->sigint_watcher_initialized) { uv_signal_init(iface->js->loop, &iface->sigint_watcher); iface->sigint_watcher.data = iface; iface->sigint_watcher_initialized = true; } if (!iface->sigint_watcher_active) { uv_signal_start(&iface->sigint_watcher, on_sigint, SIGINT); iface->sigint_watcher_active = true; } }#endif
if (is_tty && iface->terminal) process_enable_keypress_events(iface->js); iface->reading = true; process_stdin_attach_reader(iface->js, rl_feed_stdin_bytes, rl_handle_stdin_eof);}
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) != kTypeNumber) return NULL; uint64_t id = (uint64_t)js_getnum(id_val); rl_interface_t *iface = NULL; HASH_FIND(hh, js->rl_interfaces, &id, sizeof(uint64_t), iface); return iface;}
static ant_value_t rl_interface_close(ant_params_t) { 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_params_t) { 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_params_t) { 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_params_t) { 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_params_t) { 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_params_t) { 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) { if (!name) return;
static const void *dispatch[256] = { ['a'] = &&l_a, ['b'] = &&l_b, ['d'] = &&l_d, ['e'] = &&l_e, ['h'] = &&l_h, ['k'] = &&l_k, ['l'] = &&l_l, ['r'] = &&l_r, ['u'] = &&l_u, };
const unsigned char key = (unsigned char)name[0]; if (dispatch[key]) goto *dispatch[key]; return;
l_r: if (strcmp(name, "return") == 0) { if (iface->should_echo) { printf("\n"); fflush(stdout); } return; } if (strcmp(name, "right") == 0) { if (iface->line_pos < iface->line_len) iface->line_pos++; return; } return;
l_e: if (strcmp(name, "enter") == 0) { if (iface->should_echo) { printf("\n"); fflush(stdout); } return; } if (strcmp(name, "end") == 0 || (ctrl && name[1] == '\0')) { iface->line_pos = iface->line_len; } return;
l_b: if (strcmp(name, "backspace") != 0) return; if (iface->line_pos <= 0) 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--; return;
l_d: if (strcmp(name, "delete") != 0) return; if (iface->line_pos >= iface->line_len) return; memmove( iface->line_buffer + iface->line_pos, iface->line_buffer + iface->line_pos + 1, iface->line_len - iface->line_pos ); iface->line_len--; return;
l_l: if (strcmp(name, "left") == 0) { if (iface->line_pos > 0) iface->line_pos--; } return;
l_h: if (strcmp(name, "home") == 0) { iface->line_pos = 0; } return;
l_a: if (ctrl && name[1] == '\0') { iface->line_pos = 0; } return;
l_u: if (ctrl && name[1] == '\0') { iface->line_buffer[0] = '\0'; iface->line_pos = 0; iface->line_len = 0; } return;
l_k: if (ctrl && name[1] == '\0') { iface->line_buffer[iface->line_pos] = '\0'; iface->line_len = iface->line_pos; }}
static ant_value_t rl_interface_write(ant_params_t) { 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) == kTypeString) ? 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]) == kTypeNull || vtype(args[0]) == kTypeUndefined) { 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_params_t) { 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_params_t) { 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_params_t) { 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 != kTypeFunction && t != kTypeBuiltin) { 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_params_t) { 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_promise = promise; return promise;}
static ant_value_t rl_interface_get_cursor_pos(ant_params_t) { ant_value_t this_obj = js_getthis(js); rl_interface_t *iface = get_interface(js, this_obj); if (!iface) { ant_value_t result = Ant_Object_CreateBare(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 = Ant_Object_CreateBare(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_params_t) { 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 ant_value_t rl_clear_line(ant_params_t) { 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_params_t) { 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_params_t) { 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_params_t) { 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_params_t) { 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(js); return js_mkundef();}
bool has_active_readline_interfaces(ant_t *js) { rl_interface_t *iface, *tmp; HASH_ITER(hh, js->rl_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) == kTypeArray ? js_arr_len(js, queue) : 0; ant_value_t compact = 0;
if (vtype(queue) != kTypeArray || 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) == kTypeArray) 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) == kTypeArray ? js_arr_len(js, queue) : 0; ant_value_t value = js_mkundef();
if (vtype(queue) != kTypeArray || 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) != kTypePromise) break; js_resolve_promise(js, pending, js_iter_result(js, false, js_mkundef())); }}
static ant_value_t rl_async_iter_on_line(ant_params_t) { 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) == kTypePromise) { 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_params_t) { 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_params_t) { 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) != kTypeUndefined) { 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_params_t) { 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) sv_call_native_this(js, rl_interface_close, iface_obj, NULL, 0); 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(js->builtins.rl_async_iter_proto)) return js->builtins.rl_async_iter_proto;
js->builtins.rl_async_iter_proto = Ant_Object_CreateBare(js); js_set(js, js->builtins.rl_async_iter_proto, "next", Ant_Function_Create(rl_async_iter_next)); js_set(js, js->builtins.rl_async_iter_proto, "return", Ant_Function_Create(rl_async_iter_return)); js_set_sym(js, js->builtins.rl_async_iter_proto, js->sym.asyncIterator_sym, Ant_Function_Create(sym_this_cb)); js_set_tostringtag(js, js->builtins.rl_async_iter_proto, js_mkstr(js, "AsyncIterator", 13));
return js->builtins.rl_async_iter_proto;}
static ant_value_t rl_interface_async_iterator(ant_params_t) { 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 = Ant_Object_CreateBare(js); state = Ant_Object_CreateBare(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(js->builtins.rl_interface_proto)) return js->builtins.rl_interface_proto;
js->builtins.rl_interface_proto = Ant_Object_CreateBare(js); js_set_proto_init(js->builtins.rl_interface_proto, eventemitter_prototype(js));
js_set(js, js->builtins.rl_interface_proto, "close", Ant_Function_Create(rl_interface_close)); js_set(js, js->builtins.rl_interface_proto, "pause", Ant_Function_Create(rl_interface_pause)); js_set(js, js->builtins.rl_interface_proto, "resume", Ant_Function_Create(rl_interface_resume)); js_set(js, js->builtins.rl_interface_proto, "prompt", Ant_Function_Create(rl_interface_prompt)); js_set(js, js->builtins.rl_interface_proto, "setPrompt", Ant_Function_Create(rl_interface_set_prompt)); js_set(js, js->builtins.rl_interface_proto, "getPrompt", Ant_Function_Create(rl_interface_get_prompt)); js_set(js, js->builtins.rl_interface_proto, "write", Ant_Function_Create(rl_interface_write)); js_set(js, js->builtins.rl_interface_proto, "question", Ant_Function_Create(rl_interface_question_callback)); js_set(js, js->builtins.rl_interface_proto, "getCursorPos", Ant_Function_Create(rl_interface_get_cursor_pos));
js_set_getter_desc(js, js->builtins.rl_interface_proto, "line", 4, Ant_Function_Create(rl_interface_line_getter), JS_DESC_E | JS_DESC_C); js_set_getter_desc(js, js->builtins.rl_interface_proto, "cursor", 6, Ant_Function_Create(rl_interface_cursor_getter), JS_DESC_E | JS_DESC_C); js_set_getter_desc(js, js->builtins.rl_interface_proto, "closed", 6, Ant_Function_Create(rl_interface_closed_getter), JS_DESC_E | JS_DESC_C); js_set_sym(js, js->builtins.rl_interface_proto, js->sym.asyncIterator_sym, Ant_Function_Create(rl_interface_async_iterator)); js_set_tostringtag(js, js->builtins.rl_interface_proto, js_mkstr(js, "Interface", 9));
return js->builtins.rl_interface_proto;}
static ant_value_t rl_create_interface(ant_params_t) { 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->js = js; iface->id = ++js->rl_next_interface_id; iface->prompt = strdup(DEFAULT_PROMPT); iface->active_prompt = NULL; iface->line_buffer = calloc(MAX_LINE_LENGTH, 1); if (!iface->prompt || !iface->line_buffer) { free(iface->prompt); free(iface->line_buffer); free(iface); return js_mkerr(js, "out of memory"); } iface->line_pos = 0; iface->line_len = 0; iface->paused = false; iface->closed = false; iface->reading = false; iface->pending_question_promise = js_mkundef(); 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) == kTypeUndefined; iface->should_echo = is_special_object(iface->output_stream); ant_value_t history_size_val = js_get(js, options, "historySize"); iface->history_size = rl_history_capacity_from_value(history_size_val); 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) == kTypeString) { 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) == kTypeNumber) ? (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) == kTypeNumber) ? (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 == kTypeFunction || ctype == kTypeBuiltin) ? 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"); unsigned long long len = rl_history_length_from_value(len_val); rl_history_init(&iface->history, iface->history_size); unsigned long long window = (iface->history.capacity > 0) ? (unsigned long long)iface->history.capacity : 0; unsigned long long start = (window > 0 && len > window) ? len - window : 0; for (unsigned long long i = start; i < len; i++) { char key[32]; snprintf(key, sizeof(key), "%llu", i); ant_value_t item = js_get(js, history_val, key); if (vtype(item) == kTypeString) { 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, js->rl_interfaces, id, sizeof(uint64_t), iface); ant_value_t obj = Ant_Object_CreateBare(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_params_t) { ant_value_t iface_obj = rl_create_interface(js, args, nargs, js_mkundef()); if (vtype(iface_obj) == kTypeError) return iface_obj; js_set(js, iface_obj, "question", Ant_Function_Create(rl_interface_question_promise)); return iface_obj;}
ant_value_t readline_library(ant_t *js) { ant_value_t lib = Ant_Object_CreateBare(js);
js_set(js, lib, "createInterface", Ant_Function_CreateWithArity(rl_create_interface, 4)); js_set(js, lib, "clearLine", Ant_Function_CreateWithArity(rl_clear_line, 3)); js_set(js, lib, "clearScreenDown", Ant_Function_CreateWithArity(rl_clear_screen_down, 2)); js_set(js, lib, "cursorTo", Ant_Function_CreateWithArity(rl_cursor_to, 4)); js_set(js, lib, "moveCursor", Ant_Function_CreateWithArity(rl_move_cursor, 4)); js_set(js, lib, "emitKeypressEvents", Ant_Function_CreateWithArity(rl_emit_keypress_events, 1)); js_set_tostringtag(js, lib, js_mkstr(js, "readline", 8)); return lib;}
ant_value_t readline_promises_library(ant_t *js) { ant_value_t lib = Ant_Object_CreateBare(js);
js_set(js, lib, "createInterface", Ant_Function_Create(rl_create_interface_promises)); js_set(js, lib, "clearLine", Ant_Function_CreateWithArity(rl_clear_line, 3)); js_set(js, lib, "clearScreenDown", Ant_Function_CreateWithArity(rl_clear_screen_down, 2)); js_set(js, lib, "cursorTo", Ant_Function_CreateWithArity(rl_cursor_to, 4)); js_set(js, lib, "moveCursor", Ant_Function_CreateWithArity(rl_move_cursor, 4)); js_set(js, lib, "emitKeypressEvents", Ant_Function_CreateWithArity(rl_emit_keypress_events, 1)); js_set_tostringtag(js, lib, js_mkstr(js, "readline/promises", 17)); return lib;}
static void rl_interface_free(rl_interface_t *iface) { for (int i = 0; i < iface->history.count; i++) free(iface->history.lines[i]); free(iface->history.lines); free(iface->prompt); free(iface->active_prompt); free(iface->line_buffer); free(iface);}
#ifndef _WIN32static void rl_interface_sigint_closed(uv_handle_t *handle) { rl_interface_free((rl_interface_t *)handle->data);}#endif
void cleanup_readline_module(ant_t *js) { rl_interface_t *iface, *tmp; HASH_ITER(hh, js->rl_interfaces, iface, tmp) { HASH_DEL(js->rl_interfaces, iface); rl_close_interface(js, iface);#ifndef _WIN32 uv_handle_t *sigint = (uv_handle_t *)&iface->sigint_watcher; if (iface->sigint_watcher_initialized && !uv_is_closing(sigint)) { sigint->data = iface; uv_close(sigint, rl_interface_sigint_closed); continue; }#endif rl_interface_free(iface); }}
void gc_mark_readline(ant_t *js, gc_mark_fn mark) { rl_interface_t *iface, *tmp; HASH_ITER(hh, js->rl_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_promise); }}