#include #include #include #include #include "cli.h" #include "bash_history.yy.h" #include "storage.h" #include "tui.h" bool do_run = true; bool do_execute = false; void init(void); void deinit(void); void init(void) { setlocale(LC_TIME, "C"); init_storage(); char * history_file_path = getenv("HISTFILE"); if (!history_file_path) { fputs("$HISTFILE is not set, try exporting it.\n", stderr); deinit(); exit(1); } bash_history_in = fopen(history_file_path, "r"); if (!bash_history_in) { fputs("Failed to open history file.\n", stderr); deinit(); exit(1); } bash_history_lex(); init_tui(); } void deinit(void) { deinit_tui(); deinit_storage(); } void export_result(const char * const result) { if (do_execute) { /* Inject the command and a newline to STDIN directly. * Some systems could theoretically be configured to disallow it. * Not my problem. */ for (size_t i = 0; i < strlen(result); i++) { if (ioctl(STDIN_FILENO, TIOCSTI, &result[i]) == -1) { perror("ioctl TIOCSTI"); } } const char newline = '\n'; ioctl(STDIN_FILENO, TIOCSTI, &newline); } else { /* Copy to a 3th pipe file descriptor which we can * scoop up from a file and copy with READLINE_LINE. * XXX: if anyone knows a better method, please tell me */ int fd[2]; int rc = pipe(fd); (void)rc; dprintf(3, result); close(fd[0]); close(fd[1]); } } signed main(const int argc, const char * const * const argv) { // NOTE: never returns on error parse_arguments(argc, argv); init(); tui_refresh(); void * async_input([[maybe_unused]] void * arg) { while (do_run) { tui_take_input(); if (is_input_changed) { cancel_all_queries(); } } return NULL; } pthread_t query_thread; pthread_create(&query_thread, NULL, async_input, NULL); while (do_run) { entry_t entry; loop_start: if (do_redisplay) { do_redisplay = false; if (is_input_changed) { is_input_changed = false; query(get_input_line(), entry_lines, selection_offset); } else { requery(); } while (entry = get_entry(), entry.command != NULL) { if (is_input_changed) { tui_rearm(); goto loop_start; } tui_append_back(entry); } tui_refresh(); } usleep(200); } pthread_join(query_thread, NULL); query(get_input_line(), 1, selection_offset + selection_relative); export_result(get_entry().command); deinit(); return 0; }