// 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: // - // - // - // 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 #include #include #include #include #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); if (expanded == NULL) { return result; } strncpy(result, expanded, sizeof(result) - 1); result[sizeof(result) - 1] = '\0'; 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; static glob_t glob_result; static int glob_valid = 0; char pattern[1024]; if (!state) { if (glob_valid) { globfree(&glob_result); glob_valid = 0; } list_index = 0; snprintf(pattern, sizeof(pattern), "%s*", text); if (glob(pattern, GLOB_NOSORT, NULL, &glob_result) == 0) { glob_valid = 1; } else { return NULL; } } if (glob_valid && (size_t)list_index < glob_result.gl_pathc) { return strdup(glob_result.gl_pathv[list_index++]); } if (glob_valid) { globfree(&glob_result); glob_valid = 0; } 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()); }