void *connection_handler(void *socket_desc) { repl_t *repl = make_repl(); repl->current_prompt = form_prompt(repl->current_ns, false); repl->session_id = ++session_id_counter; int sock = *(int *) socket_desc; ssize_t read_size; char client_message[4096]; write(sock, repl->current_prompt, strlen(repl->current_prompt)); while ((read_size = recv(sock, client_message, 4095, 0)) > 0) { sock_to_write_to = sock; cljs_set_print_sender(&socket_sender); client_message[read_size] = '\0'; process_line(repl, strdup(client_message)); cljs_set_print_sender(NULL); sock_to_write_to = 0; write(sock, repl->current_prompt, strlen(repl->current_prompt)); } free(socket_desc); return NULL; }
int run_repl(JSContextRef ctx) { global_ctx = ctx; current_ns = strdup("cljs.user"); current_prompt = form_prompt(current_ns, false); // Per-type initialization if (!config.dumb_terminal) { char *home = getenv("HOME"); if (home != NULL) { char history_name[] = ".planck_history"; int len = strlen(home) + strlen(history_name) + 2; history_path = malloc(len * sizeof(char)); snprintf(history_path, len, "%s/%s", home, history_name); linenoiseHistoryLoad(history_path); // TODO: load keymap } linenoiseSetMultiLine(1); linenoiseSetCompletionCallback(completion); linenoiseSetHighlightCallback(highlight); linenoiseSetHighlightCancelCallback(highlight_cancel); } run_cmdline_loop(ctx); return exit_value; }
void run_cmdline_loop(repl_t *repl, JSContextRef ctx) { while (true) { char *input_line = NULL; if (config.dumb_terminal) { display_prompt(repl->current_prompt); input_line = get_input(); if (input_line == NULL) { // Ctrl-D pressed printf("\n"); break; } } else { // Handle prints while processing linenoise input if (cljs_engine_ready) { cljs_set_print_sender(ctx, &linenoisePrintNow); } // If *print-newline* is off, we need to emit a newline now, otherwise // the linenoise prompt and line editing will overwrite any printed // output on the current line. if (cljs_engine_ready && !cljs_print_newline(ctx)) { fprintf(stdout, "\n"); } char *line = linenoise(repl->current_prompt, prompt_ansi_code_for_theme(config.theme), repl->indent_space_count); // Reset printing handler back if (cljs_engine_ready) { cljs_set_print_sender(ctx, NULL); } repl->indent_space_count = 0; if (line == NULL) { if (errno == EAGAIN) { // Ctrl-C errno = 0; repl->input = NULL; empty_previous_lines(repl); repl->current_prompt = form_prompt(repl->current_ns, false); printf("\n"); continue; } else { // Ctrl-D exit_value = EXIT_SUCCESS_INTERNAL; break; } } input_line = line; } bool break_out = process_line(repl, ctx, input_line); if (break_out) { break; } } }
int run_repl() { repl_t *repl = make_repl(); s_repl = repl; repl->current_ns = strdup("cljs.user"); repl->current_prompt = form_prompt(repl->current_ns, false); // Per-type initialization if (!config.dumb_terminal) { char *home = getenv("HOME"); if (home != NULL) { char history_name[] = ".planck_history"; size_t len = strlen(home) + strlen(history_name) + 2; repl->history_path = malloc(len * sizeof(char)); snprintf(repl->history_path, len, "%s/%s", home, history_name); linenoiseHistoryLoad(repl->history_path); exit_value = load_keymap(home); if (exit_value != EXIT_SUCCESS) { return exit_value; } } linenoiseSetMultiLine(1); linenoiseSetCompletionCallback(completion); linenoiseSetHighlightCallback(highlight); linenoiseSetHighlightCancelCallback(highlight_cancel); } if (!config.dumb_terminal) { cljs_set_print_sender(&linenoisePrintNow); } if (config.socket_repl_port) { pthread_t thread; pthread_create(&thread, NULL, accept_connections, NULL); } run_cmdline_loop(repl); return exit_value; }
bool process_line(repl_t *repl, char *input_line) { // Accumulate input lines if (repl->input == NULL) { repl->input = input_line; } else { repl->input = realloc(repl->input, (strlen(repl->input) + strlen(input_line) + 2) * sizeof(char)); sprintf(repl->input + strlen(repl->input), "\n%s", input_line); } repl->num_previous_lines += 1; repl->previous_lines = realloc(repl->previous_lines, repl->num_previous_lines * sizeof(char *)); repl->previous_lines[repl->num_previous_lines - 1] = strdup(input_line); // Check for explicit exit if (strcmp(repl->input, ":cljs/quit") == 0 || strcmp(repl->input, "quit") == 0 || strcmp(repl->input, "exit") == 0) { if (repl->session_id == 0) { exit_value = EXIT_SUCCESS_INTERNAL; } return true; } // Add input line to history if (repl->history_path != NULL && !is_whitespace(repl->input)) { linenoiseHistoryAdd(input_line); linenoiseHistorySave(repl->history_path); } // Check if we now have readable forms // and if so, evaluate them bool done = false; char *balance_text = NULL; while (!done) { if ((balance_text = cljs_is_readable(repl->input)) != NULL) { repl->input[strlen(repl->input) - strlen(balance_text)] = '\0'; if (!is_whitespace(repl->input)) { // Guard against empty string being read return_termsize = !config.dumb_terminal; if (repl->session_id == 0) { set_int_handler(); } // TODO: set exit value const char *theme = repl->session_id == 0 ? config.theme : "dumb"; evaluate_source("text", repl->input, true, true, repl->current_ns, theme, true, repl->session_id); if (repl->session_id == 0) { clear_int_handler(); } return_termsize = false; if (exit_value != 0) { free(repl->input); return true; } } else { printf("\n"); } // Now that we've evaluated the input, reset for next round free(repl->input); repl->input = balance_text; empty_previous_lines(repl); // Fetch the current namespace and use it to set the prompt free(repl->current_ns); free(repl->current_prompt); repl->current_ns = cljs_get_current_ns(); repl->current_prompt = form_prompt(repl->current_ns, false); if (is_whitespace(balance_text)) { done = true; free(repl->input); repl->input = NULL; } } else { // Prepare for reading non-1st of input with secondary prompt if (repl->history_path != NULL) { repl->indent_space_count = cljs_indent_space_count(repl->input); } free(repl->current_prompt); repl->current_prompt = form_prompt(repl->current_ns, true); done = true; } } return false; }