#include #include #include #include #include "db.h" #include "utils.h" #include "history.h" #include "config.h" #include "shell_integration.h" #include "tui.h" #define RHISTORY_VERSION "0.1.0" // Command handlers int cmd_search(int argc, char **argv); int cmd_import(int argc, char **argv); int cmd_list(int argc, char **argv); int cmd_stats(int argc, char **argv); int cmd_delete(int argc, char **argv); int cmd_init(int argc, char **argv); int cmd_config(int argc, char **argv); int cmd_record(int argc, char **argv); // Internal void print_help(void); void print_version(void); int main(int argc, char **argv) { if (argc < 2) { return cmd_search(argc, argv); } if (strcmp(argv[1], "search") == 0) { return cmd_search(argc - 1, argv + 1); } else if (strcmp(argv[1], "import") == 0) { return cmd_import(argc - 1, argv + 1); } else if (strcmp(argv[1], "list") == 0) { return cmd_list(argc - 1, argv + 1); } else if (strcmp(argv[1], "stats") == 0) { return cmd_stats(argc - 1, argv + 1); } else if (strcmp(argv[1], "delete") == 0) { return cmd_delete(argc - 1, argv + 1); } else if (strcmp(argv[1], "init") == 0) { return cmd_init(argc - 1, argv + 1); } else if (strcmp(argv[1], "config") == 0) { return cmd_config(argc - 1, argv + 1); } else if (strcmp(argv[1], "record") == 0) { return cmd_record(argc - 1, argv + 1); } else if (strcmp(argv[1], "help") == 0 || strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0) { print_help(); return 0; } else if (strcmp(argv[1], "version") == 0 || strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-v") == 0) { print_version(); return 0; } else { // Default to search if unknown command, or maybe print help? // Prompt says "rhistory [OPTIONS] [COMMAND]". // If it starts with -, it's options for search probably. if (argv[1][0] == '-') { return cmd_search(argc, argv); } fprintf(stderr, "Unknown command: %s\n", argv[1]); print_help(); return 1; } } void print_help(void) { printf("rhistory %s\n", RHISTORY_VERSION); printf("Usage: rhistory [COMMAND] [OPTIONS]\n\n"); printf("Commands:\n"); printf(" search Search history (default)\n"); printf(" import Import history from shell file\n"); printf(" list List history entries\n"); printf(" stats Show statistics\n"); printf(" delete Delete entries\n"); printf(" init Generate shell integration code\n"); printf(" config Manage configuration\n"); printf(" help Show this help\n"); printf(" version Show version\n"); } void print_version(void) { printf("rhistory %s\n", RHISTORY_VERSION); } // Database Helper bool setup_db(void) { char *data_dir = get_data_dir(); if (!ensure_directory_exists(data_dir)) { fprintf(stderr, "Failed to create data directory: %s\n", data_dir); free(data_dir); return false; } char *db_path = join_path(data_dir, "history.db"); bool success = db_init(db_path); free(db_path); free(data_dir); return success; } // Stub implementations #include "shell_integration.h" #include "search.h" #include // ... int cmd_search(int argc, char **argv) { if (!setup_db()) return 1; SearchQuery query; memset(&query, 0, sizeof(query)); query.exit_code = -1; query.limit = 20; static struct option long_options[] = { {"interactive", no_argument, 0, 'i'}, {"exit", required_argument, 0, 'e'}, {"cwd", required_argument, 0, 'c'}, {"host", required_argument, 0, 'h'}, {"session", required_argument, 0, 's'}, {"limit", required_argument, 0, 'l'}, {"reverse", no_argument, 0, 'r'}, {"cmd-only", no_argument, 0, 1001}, {0, 0, 0, 0} }; bool interactive = false; bool cmd_only = false; int opt_index = 0; int c; // Reset getopt optind = 1; while ((c = getopt_long(argc, argv, "ie:c:h:s:l:r", long_options, &opt_index)) != -1) { switch (c) { case 'i': interactive = true; break; case 'e': query.exit_code = atoi(optarg); break; case 'c': query.cwd = optarg; break; case 'h': query.hostname = optarg; break; case 's': query.session = optarg; break; case 'l': query.limit = atoi(optarg); break; case 'r': query.reverse = true; break; case 1001: cmd_only = true; break; } } if (optind < argc) { query.query_string = argv[optind]; } if (interactive) { tui_start(&query); } else { SearchResult *res = search_perform(&query); if (!res) { fprintf(stderr, "Search failed.\n"); db_close(); return 1; } for (int i = 0; i < res->count; i++) { HistoryEntry *e = res->entries[i]; if (cmd_only) { printf("%s\n", e->command); } else { // Format timestamp time_t t = (time_t)e->timestamp; struct tm *tm = localtime(&t); char time_str[64]; strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", tm); printf("%s | %s | %s | %dms | %s\n", time_str, e->hostname, e->cwd, e->duration, e->command); } } search_free_result(res); } db_close(); return 0; } int cmd_import(int argc, char **argv) { if (!setup_db()) return 1; const char *shell = "auto"; if (argc > 1) { shell = argv[1]; } history_import(shell); db_close(); return 0; } int cmd_list(int argc, char **argv) { if (!setup_db()) return 1; printf("List command not implemented yet.\n"); db_close(); return 0; } int cmd_stats(int argc, char **argv) { if (!setup_db()) return 1; int limit = 10; static struct option long_options[] = { {"top", required_argument, 0, 't'}, {0, 0, 0, 0} }; int opt_index = 0; int c; optind = 1; while ((c = getopt_long(argc, argv, "t:", long_options, &opt_index)) != -1) { switch (c) { case 't': limit = atoi(optarg); break; } } history_stats(limit); db_close(); return 0; } int cmd_delete(int argc, char **argv) { if (!setup_db()) return 1; printf("Delete command not implemented yet.\n"); db_close(); return 0; } #include "shell_integration.h" // ... (other includes) int cmd_init(int argc, char **argv) { if (argc > 1) { if (!shell_integration_init(argv[1])) { fprintf(stderr, "Unsupported shell: %s. Supported: bash, zsh, fish\n", argv[1]); return 1; } } else { printf("Usage: rhistory init [bash|zsh|fish]\n"); return 1; } return 0; } int cmd_config(int argc, char **argv) { printf("Config command not implemented yet.\n"); return 0; } int cmd_record(int argc, char **argv) { if (!setup_db()) return 1; char *command = NULL; char *cwd = NULL; int exit_code = 0; int duration = 0; char *hostname = NULL; char *session = NULL; char *shell = NULL; static struct option long_options[] = { {"command", required_argument, 0, 'c'}, {"cwd", required_argument, 0, 'w'}, {"exit-code", required_argument, 0, 'e'}, {"duration", required_argument, 0, 'd'}, {"hostname", required_argument, 0, 'H'}, {"session", required_argument, 0, 's'}, {"shell", required_argument, 0, 'S'}, {0, 0, 0, 0} }; int opt_index = 0; int c; while ((c = getopt_long(argc, argv, "", long_options, &opt_index)) != -1) { switch (c) { case 'c': command = optarg; break; case 'w': cwd = optarg; break; case 'e': exit_code = atoi(optarg); break; case 'd': duration = atoi(optarg); break; case 'H': hostname = optarg; break; case 's': session = optarg; break; case 'S': shell = optarg; break; } } if (command && cwd) { if (history_record(command, cwd, exit_code, duration, hostname, session, shell)) { // success, silent } else { fprintf(stderr, "Failed to record history.\n"); } } else { fprintf(stderr, "Missing required arguments for record.\n"); } db_close(); return 0; }