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; } } }
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; }