// Written by retoor@molodetz.nl // This source code provides command-line input functionalities with // autocomplete and history features using the readline library. It allows users // to complete commands and manage input history. // External includes: // - <readline/readline.h> // - <readline/history.h> // - <glob.h> // MIT License: Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction. #include "utils.h" #include <glob.h> #include <readline/history.h> #include <readline/readline.h> #include <stdbool.h> #include <string.h> #define HISTORY_FILE "~/.r_history" bool line_initialized = false; char *get_history_file() { static char result[4096]; result[0] = 0; char *expanded = expand_home_directory(HISTORY_FILE); strcpy(result, expanded); free(expanded); return result; } char *line_command_generator(const char *text, int state) { static int list_index, len = 0; const char *commands[] = {"help", "exit", "list", "review", "refactor", "obfuscate", "!verbose", "!dump", "!model", "!debug", NULL}; if (!state) { list_index = 0; len = strlen(text); } while (commands[list_index]) { const char *command = commands[list_index++]; if (strncmp(command, text, len) == 0) { return strdup(command); } } return NULL; } char *line_file_generator(const char *text, int state) { static int list_index; glob_t glob_result; char pattern[1024]; if (!state) { list_index = 0; snprintf(pattern, sizeof(pattern), "%s*", text); // Create a pattern for glob glob(pattern, GLOB_NOSORT, NULL, &glob_result); } if (list_index < glob_result.gl_pathc) { return strdup(glob_result.gl_pathv[list_index++]); } globfree(&glob_result); return NULL; } char **line_command_completion(const char *text, int start, int end) { rl_attempted_completion_over = 1; // Check if the input is a file path if (start > 0 && text[0] != ' ') { return rl_completion_matches(text, line_file_generator); } return rl_completion_matches(text, line_command_generator); } void line_init() { if (!line_initialized) { rl_attempted_completion_function = line_command_completion; line_initialized = true; read_history(get_history_file()); } } char *line_read(char *prefix) { char *data = readline(prefix); if (!(data && *data)) { free(data); return NULL; } return data; } void line_add_history(char *data) { add_history(data); write_history(get_history_file()); }