From 08fb0af5028b902177b1feb940885d2adc802b64 Mon Sep 17 00:00:00 2001 From: marcusDenslow Date: Mon, 28 Apr 2025 12:35:52 +0200 Subject: [PATCH] first commit --- Makefile | 22 + aliases.c | 488 ++++++++++++++++++++ aliases.h | 63 +++ aliases.o | Bin 0 -> 24136 bytes autocorrect.c | 168 +++++++ autocorrect.h | 50 ++ autocorrect.o | Bin 0 -> 10808 bytes bookmarks.c | 409 +++++++++++++++++ bookmarks.h | 57 +++ bookmarks.o | Bin 0 -> 22640 bytes builtins.c | 764 +++++++++++++++++++++++++++++++ builtins.h | 100 ++++ builtins.o | Bin 0 -> 44280 bytes common.h | 115 +++++ countdown_timer.c | 306 +++++++++++++ countdown_timer.h | 57 +++ countdown_timer.o | Bin 0 -> 16080 bytes favorite_cities.c | 324 +++++++++++++ favorite_cities.h | 50 ++ favorite_cities.o | Bin 0 -> 18480 bytes filters.c | 510 +++++++++++++++++++++ filters.h | 66 +++ filters.o | Bin 0 -> 27056 bytes fzf_native.c | 571 +++++++++++++++++++++++ fzf_native.h | 57 +++ fzf_native.o | Bin 0 -> 26152 bytes git_integration.c | 154 +++++++ git_integration.h | 43 ++ git_integration.o | Bin 0 -> 11296 bytes grep.c | 54 +++ grep.h | 28 ++ grep.o | Bin 0 -> 4944 bytes line_reader.c | 1039 ++++++++++++++++++++++++++++++++++++++++++ line_reader.h | 57 +++ line_reader.o | Bin 0 -> 42264 bytes main.c | 26 ++ main.o | Bin 0 -> 4072 bytes mingw-get-setup.exe | Bin 0 -> 86528 bytes persistent_history.c | 502 ++++++++++++++++++++ persistent_history.h | 85 ++++ persistent_history.o | Bin 0 -> 25880 bytes ps_command.c | 113 +++++ ps_command.o | Bin 0 -> 10784 bytes rg_selection.txt | 0 ripgrep.c | 746 ++++++++++++++++++++++++++++++ ripgrep.h | 26 ++ ripgrep.o | Bin 0 -> 33664 bytes shell | Bin 0 -> 266912 bytes shell.bat | 2 + shell.c | 591 ++++++++++++++++++++++++ shell.exe | Bin 0 -> 703573 bytes shell.h | 125 +++++ shell.o | Bin 0 -> 28696 bytes structured_data.c | 479 +++++++++++++++++++ structured_data.h | 70 +++ structured_data.o | Bin 0 -> 26904 bytes tab_complete.c | 460 +++++++++++++++++++ tab_complete.h | 58 +++ tab_complete.o | Bin 0 -> 24232 bytes themes.c | 481 +++++++++++++++++++ themes.h | 92 ++++ themes.o | Bin 0 -> 19616 bytes timer.c | 97 ++++ timer.h | 38 ++ timer.o | Bin 0 -> 7776 bytes weather.c | 75 +++ weather.h | 8 + weather.o | Bin 0 -> 10064 bytes 68 files changed, 9626 insertions(+) create mode 100644 Makefile create mode 100644 aliases.c create mode 100644 aliases.h create mode 100644 aliases.o create mode 100644 autocorrect.c create mode 100644 autocorrect.h create mode 100644 autocorrect.o create mode 100644 bookmarks.c create mode 100644 bookmarks.h create mode 100644 bookmarks.o create mode 100644 builtins.c create mode 100644 builtins.h create mode 100644 builtins.o create mode 100644 common.h create mode 100644 countdown_timer.c create mode 100644 countdown_timer.h create mode 100644 countdown_timer.o create mode 100644 favorite_cities.c create mode 100644 favorite_cities.h create mode 100644 favorite_cities.o create mode 100644 filters.c create mode 100644 filters.h create mode 100644 filters.o create mode 100644 fzf_native.c create mode 100644 fzf_native.h create mode 100644 fzf_native.o create mode 100644 git_integration.c create mode 100644 git_integration.h create mode 100644 git_integration.o create mode 100644 grep.c create mode 100644 grep.h create mode 100644 grep.o create mode 100644 line_reader.c create mode 100644 line_reader.h create mode 100644 line_reader.o create mode 100644 main.c create mode 100644 main.o create mode 100644 mingw-get-setup.exe create mode 100644 persistent_history.c create mode 100644 persistent_history.h create mode 100644 persistent_history.o create mode 100644 ps_command.c create mode 100644 ps_command.o create mode 100644 rg_selection.txt create mode 100644 ripgrep.c create mode 100644 ripgrep.h create mode 100644 ripgrep.o create mode 100755 shell create mode 100644 shell.bat create mode 100644 shell.c create mode 100644 shell.exe create mode 100644 shell.h create mode 100644 shell.o create mode 100644 structured_data.c create mode 100644 structured_data.h create mode 100644 structured_data.o create mode 100644 tab_complete.c create mode 100644 tab_complete.h create mode 100644 tab_complete.o create mode 100644 themes.c create mode 100644 themes.h create mode 100644 themes.o create mode 100644 timer.c create mode 100644 timer.h create mode 100644 timer.o create mode 100644 weather.c create mode 100644 weather.h create mode 100644 weather.o diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9e7e92d --- /dev/null +++ b/Makefile @@ -0,0 +1,22 @@ +CC = gcc +CFLAGS = -Wall -Wextra -g +LIBS = -lm + +# Get all .c files +SOURCES = $(wildcard *.c) +# Generate object file names from source file names +OBJECTS = $(SOURCES:.c=.o) +TARGET = shell + +all: $(TARGET) + +$(TARGET): $(OBJECTS) + $(CC) $(CFLAGS) -o $@ $^ $(LIBS) + +%.o: %.c + $(CC) $(CFLAGS) -c $< -o $@ + +clean: + rm -f $(OBJECTS) $(TARGET) + +.PHONY: all clean \ No newline at end of file diff --git a/aliases.c b/aliases.c new file mode 100644 index 0000000..2df9a76 --- /dev/null +++ b/aliases.c @@ -0,0 +1,488 @@ +/** + * aliases.c + * Implementation of shell alias functionality + */ + +#include "aliases.h" +#include "builtins.h" +#include +#include + +// Global variables for alias storage +AliasEntry *aliases = NULL; +int alias_count = 0; +int alias_capacity = 0; + +// Path to the aliases file +char aliases_file_path[PATH_MAX]; + +/** + * Initialize the alias system + */ +void init_aliases(void) { + // Set initial capacity + alias_capacity = 10; + aliases = (AliasEntry*)malloc(alias_capacity * sizeof(AliasEntry)); + + if (!aliases) { + fprintf(stderr, "lsh: allocation error in init_aliases\n"); + return; + } + + // Determine aliases file location - in user's home directory + char *home_dir = getenv("HOME"); + if (home_dir) { + snprintf(aliases_file_path, PATH_MAX, "%s/.lsh_aliases", home_dir); + } else { + // Fallback to current directory if HOME not available + strcpy(aliases_file_path, ".lsh_aliases"); + } + + // Load aliases from file + load_aliases(); +} + +/** + * Clean up the alias system + */ +void cleanup_aliases(void) { + if (!aliases) return; + + // Free all alias entries + for (int i = 0; i < alias_count; i++) { + free(aliases[i].name); + free(aliases[i].command); + } + + // Free the array + free(aliases); + aliases = NULL; + alias_count = 0; + alias_capacity = 0; +} + +/** + * Shutdown the alias system + */ +void shutdown_aliases(void) { + // Save aliases to file + save_aliases(); + + // Clean up + cleanup_aliases(); +} + +/** + * Load aliases from file + */ +int load_aliases(void) { + FILE *fp = fopen(aliases_file_path, "r"); + if (!fp) { + return 0; // File doesn't exist or can't be opened + } + + char line[LSH_RL_BUFSIZE]; + char name[LSH_RL_BUFSIZE / 2]; + char command[LSH_RL_BUFSIZE / 2]; + + while (fgets(line, sizeof(line), fp)) { + // Skip comments and empty lines + if (line[0] == '#' || line[0] == '\n') { + continue; + } + + // Parse alias definitions (name=command) + if (sscanf(line, "%s=%s", name, command) == 2) { + add_alias(name, command); + } + } + + fclose(fp); + return 1; +} + +/** + * Save aliases to file + */ +int save_aliases(void) { + FILE *fp = fopen(aliases_file_path, "w"); + if (!fp) { + fprintf(stderr, "lsh: error saving aliases to %s\n", aliases_file_path); + return 0; + } + + // Write file header + time_t t = time(NULL); + struct tm *tm_info = localtime(&t); + char timestamp[26]; + strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", tm_info); + + fprintf(fp, "# LSH Aliases - Last updated: %s\n\n", timestamp); + + // Write each alias + for (int i = 0; i < alias_count; i++) { + fprintf(fp, "%s=%s\n", aliases[i].name, aliases[i].command); + } + + fclose(fp); + return 1; +} + +/** + * Add a new alias + */ +int add_alias(const char *name, const char *command) { + if (!name || !command) { + return 0; + } + + // Check if alias already exists, update it if it does + for (int i = 0; i < alias_count; i++) { + if (strcmp(aliases[i].name, name) == 0) { + // Update existing alias + free(aliases[i].command); + aliases[i].command = strdup(command); + return 1; + } + } + + // Check if we need to expand the array + if (alias_count >= alias_capacity) { + alias_capacity *= 2; + AliasEntry *new_aliases = (AliasEntry*)realloc(aliases, alias_capacity * sizeof(AliasEntry)); + if (!new_aliases) { + fprintf(stderr, "lsh: allocation error in add_alias\n"); + return 0; + } + aliases = new_aliases; + } + + // Add new alias + aliases[alias_count].name = strdup(name); + aliases[alias_count].command = strdup(command); + alias_count++; + + return 1; +} + +/** + * Remove an alias + */ +int remove_alias(const char *name) { + if (!name) { + return 0; + } + + for (int i = 0; i < alias_count; i++) { + if (strcmp(aliases[i].name, name) == 0) { + // Free memory for this alias + free(aliases[i].name); + free(aliases[i].command); + + // Shift remaining aliases down + for (int j = i; j < alias_count - 1; j++) { + aliases[j] = aliases[j + 1]; + } + + alias_count--; + return 1; + } + } + + return 0; // Alias not found +} + +/** + * Find an alias by name + */ +AliasEntry* find_alias(const char *name) { + for (int i = 0; i < alias_count; i++) { + if (strcmp(aliases[i].name, name) == 0) { + return &aliases[i]; + } + } + return NULL; +} + +/** + * Expand a command line by replacing aliases + */ +char* expand_aliases(const char *command) { + if (!command) { + return NULL; + } + + char *result = strdup(command); + if (!result) return NULL; + + // Copy the command for tokenization + char *cmd_copy = strdup(result); + if (!cmd_copy) { + free(result); + return NULL; + } + + // Extract the first word (command name) + char *token = strtok(cmd_copy, " \t"); + if (!token) { + free(cmd_copy); + return result; + } + + // Look up the alias + AliasEntry *alias = find_alias(token); + if (alias) { + // Get the args after the command + char *args = strchr(command, ' '); + + // Allocate new buffer for expanded command + free(result); + if (args) { + // Concatenate alias command and original args + result = malloc(strlen(alias->command) + strlen(args) + 1); + if (result) { + strcpy(result, alias->command); + strcat(result, args); + } + } else { + // No args, just use alias command + result = strdup(alias->command); + } + } + + free(cmd_copy); + return result; +} + +/** + * Command handler for the "alias" command + */ +int lsh_alias(char **args) { + // No arguments - list all aliases + if (args[1] == NULL) { + for (int i = 0; i < alias_count; i++) { + printf("alias %s='%s'\n", aliases[i].name, aliases[i].command); + } + return 1; + } + + // Pre-defined aliases + if (strcmp(args[1], "vim-mode") == 0) { + // Configure aliases for Vim-like operation + add_alias("v", "vim"); + + // Check for neovim first + FILE *test_nvim = popen("which nvim 2>/dev/null", "r"); + if (test_nvim) { + char buffer[128]; + if (fgets(buffer, sizeof(buffer), test_nvim) != NULL) { + // Neovim found, use it as preferred editor + pclose(test_nvim); + add_alias("e", "nvim"); + printf("Vim mode activated (using Neovim)\n"); + return 1; + } + pclose(test_nvim); + + // Check for regular vim + FILE *test_vim = popen("which vim 2>/dev/null", "r"); + if (test_vim) { + char buffer[128]; + if (fgets(buffer, sizeof(buffer), test_vim) != NULL) { + // Vim found + pclose(test_vim); + add_alias("e", "vim"); + printf("Vim mode activated\n"); + return 1; + } + pclose(test_vim); + } + } + + // Fallback to vi if neither vim nor neovim is found + add_alias("e", "vi"); + printf("Vim mode activated (using vi)\n"); + return 1; + } else if (strcmp(args[1], "emacs-mode") == 0) { + // Configure aliases for Emacs-like operation + FILE *test_emacs = popen("which emacs 2>/dev/null", "r"); + if (test_emacs) { + char buffer[128]; + if (fgets(buffer, sizeof(buffer), test_emacs) != NULL) { + pclose(test_emacs); + add_alias("e", "emacs -nw"); + printf("Emacs mode activated\n"); + return 1; + } + pclose(test_emacs); + } + + printf("Emacs not found. Emacs mode not activated.\n"); + return 1; + } + + // Format: alias name=command + char *equals = strchr(args[1], '='); + if (equals) { + // Split at equals sign + *equals = '\0'; + char *name = args[1]; + char *command = equals + 1; + + // Remove quotes around command if present + if (*command == '\'' || *command == '"') { + command++; + char *end = command + strlen(command) - 1; + if (*end == '\'' || *end == '"') { + *end = '\0'; + } + } + + add_alias(name, command); + printf("Alias added: %s='%s'\n", name, command); + } else if (args[2] != NULL) { + // Format: alias name command + add_alias(args[1], args[2]); + printf("Alias added: %s='%s'\n", args[1], args[2]); + } else { + // Just a name - show this specific alias + AliasEntry *alias = find_alias(args[1]); + if (alias) { + printf("alias %s='%s'\n", alias->name, alias->command); + } else { + printf("Alias '%s' not found\n", args[1]); + } + } + + // Save aliases to file + save_aliases(); + + return 1; +} + +/** + * Command handler for the "unalias" command + */ +int lsh_unalias(char **args) { + if (args[1] == NULL) { + printf("unalias: missing argument\n"); + return 1; + } + + if (remove_alias(args[1])) { + printf("Alias '%s' removed\n", args[1]); + + // Save aliases to file + save_aliases(); + } else { + printf("Alias '%s' not found\n", args[1]); + } + + return 1; +} + +/** + * Command handler to show all aliases + */ +int lsh_aliases(char **args) { + for (int i = 0; i < alias_count; i++) { + printf("alias %s='%s'\n", aliases[i].name, aliases[i].command); + } + return 1; +} + +/** + * Get alias names for tab completion + */ +char** get_alias_names(int *count) { + if (alias_count == 0 || !count) { + *count = 0; + return NULL; + } + + char **names = (char**)malloc(alias_count * sizeof(char*)); + if (!names) { + *count = 0; + return NULL; + } + + for (int i = 0; i < alias_count; i++) { + names[i] = strdup(aliases[i].name); + } + + *count = alias_count; + return names; +} + +/** + * Expand alias in args array + */ +char** expand_alias(char **args) { + if (!args || !args[0]) { + return NULL; + } + + // Check if the command is an alias + AliasEntry *alias = find_alias(args[0]); + if (!alias) { + return NULL; + } + + // Count tokens in alias command + char *alias_copy = strdup(alias->command); + if (!alias_copy) { + return NULL; + } + + char **alias_tokens = malloc(LSH_TOK_BUFSIZE * sizeof(char*)); + if (!alias_tokens) { + free(alias_copy); + return NULL; + } + + char *token, *rest = alias_copy; + int token_count = 0; + + while ((token = strtok_r(rest, " \t", &rest)) != NULL) { + alias_tokens[token_count++] = strdup(token); + + if (token_count >= LSH_TOK_BUFSIZE) { + fprintf(stderr, "lsh: alias expansion: too many tokens\n"); + break; + } + } + + free(alias_copy); + + // Count original arguments + int arg_count = 0; + while (args[arg_count] != NULL) { + arg_count++; + } + + // Allocate space for expanded command + char **expanded_args = malloc((token_count + arg_count) * sizeof(char*)); + if (!expanded_args) { + for (int i = 0; i < token_count; i++) { + free(alias_tokens[i]); + } + free(alias_tokens); + return NULL; + } + + // Copy alias tokens + for (int i = 0; i < token_count; i++) { + expanded_args[i] = alias_tokens[i]; + } + + // Copy remaining arguments (skip the command) + for (int i = 1; i < arg_count; i++) { + expanded_args[token_count + i - 1] = strdup(args[i]); + } + + // Null-terminate the array + expanded_args[token_count + arg_count - 1] = NULL; + + free(alias_tokens); + return expanded_args; +} \ No newline at end of file diff --git a/aliases.h b/aliases.h new file mode 100644 index 0000000..5423af8 --- /dev/null +++ b/aliases.h @@ -0,0 +1,63 @@ +/** + * aliases.h + * Definitions for shell alias functionality + */ + +#ifndef ALIASES_H +#define ALIASES_H + +#include "common.h" + +// Structure to represent an alias +typedef struct AliasEntry { + char *name; // Alias name (command to type) + char *command; // The command it expands to +} AliasEntry; + +// Initialize alias system +void init_aliases(void); + +// Clean up alias system +void cleanup_aliases(void); + +// Shutdown the alias system +void shutdown_aliases(void); + +// Load aliases from file +int load_aliases(void); + +// Save aliases to file +int save_aliases(void); + +// Add a new alias +int add_alias(const char *name, const char *command); + +// Remove an alias +int remove_alias(const char *name); + +// Find an alias by name +AliasEntry* find_alias(const char *name); + +// Expand a command line by replacing aliases +char* expand_aliases(const char *command); + +// Command handler for the "alias" command +int lsh_alias(char **args); + +// Command handler for the "unalias" command +int lsh_unalias(char **args); + +// Command handler to list all aliases +int lsh_aliases(char **args); + +// Get alias names for tab completion +char** get_alias_names(int *count); + +// Expand alias in args array +char** expand_alias(char **args); + +// Global variables for alias storage +extern AliasEntry *aliases; +extern int alias_count; + +#endif // ALIASES_H \ No newline at end of file diff --git a/aliases.o b/aliases.o new file mode 100644 index 0000000000000000000000000000000000000000..a4beddd7fbd9bae0c1367421ea845d7668f6b22a GIT binary patch literal 24136 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 literal 0 HcmV?d00001 diff --git a/autocorrect.c b/autocorrect.c new file mode 100644 index 0000000..c735d89 --- /dev/null +++ b/autocorrect.c @@ -0,0 +1,168 @@ +/** + * autocorrect.c + * Implementation of command auto-correction functionality + */ + +#include "autocorrect.h" +#include "builtins.h" + +/** + * Calculate Levenshtein distance between two strings + * Used to determine similarity between mistyped command and potential + * corrections + */ +int levenshtein_distance(const char *s1, const char *s2) { + int len1 = strlen(s1); + int len2 = strlen(s2); + + // Create a matrix to store distances + int **matrix = (int **)malloc((len1 + 1) * sizeof(int *)); + if (!matrix) return -1; + + for (int i = 0; i <= len1; i++) { + matrix[i] = (int *)malloc((len2 + 1) * sizeof(int)); + if (!matrix[i]) { + for (int j = 0; j < i; j++) { + free(matrix[j]); + } + free(matrix); + return -1; + } + } + + // Initialize the matrix + for (int i = 0; i <= len1; i++) { + matrix[i][0] = i; + } + for (int j = 0; j <= len2; j++) { + matrix[0][j] = j; + } + + // Fill the matrix + for (int i = 1; i <= len1; i++) { + for (int j = 1; j <= len2; j++) { + int cost = (s1[i - 1] == s2[j - 1]) ? 0 : 1; + matrix[i][j] = min3(matrix[i - 1][j] + 1, // deletion + matrix[i][j - 1] + 1, // insertion + matrix[i - 1][j - 1] + cost // substitution + ); + } + } + + // Get the result and free the matrix + int result = matrix[len1][len2]; + for (int i = 0; i <= len1; i++) { + free(matrix[i]); + } + free(matrix); + + return result; +} + +/** + * Helper function to find minimum of three integers + */ +int min3(int a, int b, int c) { + int min = a; + if (b < min) + min = b; + if (c < min) + min = c; + return min; +} + +/** + * Initialize the autocorrect system + */ +void init_autocorrect(void) { + // No initialization required currently +} + +/** + * Shutdown the autocorrect system + */ +void shutdown_autocorrect(void) { + // No cleanup required currently +} + +/** + * Check a command for possible corrections and suggest alternative + */ + +/** + * Check a command for possible corrections and suggest alternative + */ + +/** + * Check a command for possible corrections and suggest alternative + */ +char **check_for_corrections(char **args) { + if (!args || !args[0]) { + return NULL; + } + + const char *command = args[0]; + + // Skip very short commands or commands that start with ./ or / + if (strlen(command) < 3 || command[0] == '.' || command[0] == '/') { + return NULL; + } + + // Don't try to correct arguments, only the command itself + // Check if the command is valid, if it is, no correction needed + if (is_valid_command(command)) { + return NULL; + } + + // List of common commands to check against + const char *common_commands[] = { + "ls", "cd", "grep", "find", "cat", "mv", "cp", "rm", "mkdir", "rmdir", + "chmod", "chown", "ps", "top", "df", "du", "free", "mount", "umount", + "tar", "zip", "unzip", "ssh", "scp", "ping", "netstat", "ifconfig", + "route", "traceroute", "wget", "curl", "apt", "apt-get", "yum", "dnf", + "pacman", "git", "make", "gcc", "g++", "python", "python3", "node", + "npm", "vim", "nano", "history", "clear", "exit", "alias", "man", "help", + "touch", "echo", "pwd", "sudo", "shutdown", "reboot", NULL + }; + + // Check built-in commands too + int best_distance = 3; // Maximum edit distance to consider a correction + const char *best_match = NULL; + + // First check among built-in commands + for (int i = 0; i < lsh_num_builtins(); i++) { + int distance = levenshtein_distance(command, builtin_str[i]); + if (distance < best_distance) { + best_distance = distance; + best_match = builtin_str[i]; + } + } + + // Then check common commands + for (int i = 0; common_commands[i] != NULL; i++) { + int distance = levenshtein_distance(command, common_commands[i]); + if (distance < best_distance) { + best_distance = distance; + best_match = common_commands[i]; + } + } + + // If we found a good match, suggest it + if (best_match) { + printf("Command '%s' not found. Did you mean '%s'?\n", command, best_match); + // No longer waiting for input - just return NULL + } + + return NULL; +} + +/** + * Count the number of arguments in a NULL-terminated array + */ +int count_args(char **args) { + int count = 0; + while (args[count] != NULL) { + count++; + } + return count; +} diff --git a/autocorrect.h b/autocorrect.h new file mode 100644 index 0000000..9f31b7c --- /dev/null +++ b/autocorrect.h @@ -0,0 +1,50 @@ +/** + * autocorrect.h + * Header for command auto-correction functionality + */ + +#ifndef AUTOCORRECT_H +#define AUTOCORRECT_H + +#include "common.h" +#include "line_reader.h" +#include + +/** + * Calculate Levenshtein distance between two strings + * + * @param s1 First string + * @param s2 Second string + * @return Edit distance between the strings + */ +int levenshtein_distance(const char *s1, const char *s2); + +/** + * Helper function to find minimum of three integers + */ +int min3(int a, int b, int c); + +/** + * Initialize the autocorrect system + */ +void init_autocorrect(void); + +/** + * Shutdown the autocorrect system + */ +void shutdown_autocorrect(void); + +/** + * Check a command for possible corrections + * + * @param args Command arguments + * @return Corrected arguments array (must be freed by caller) or NULL if no correction + */ +char **check_for_corrections(char **args); + +/** + * Count the number of arguments in a NULL-terminated array + */ +int count_args(char **args); + +#endif // AUTOCORRECT_H \ No newline at end of file diff --git a/autocorrect.o b/autocorrect.o new file mode 100644 index 0000000000000000000000000000000000000000..dfeb1d3c13d7d97d4a9e8d51ff2feee10f4be97c GIT binary patch literal 10808 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 JhHcvZe*k}5HIV=S literal 0 HcmV?d00001 diff --git a/bookmarks.c b/bookmarks.c new file mode 100644 index 0000000..1ee629e --- /dev/null +++ b/bookmarks.c @@ -0,0 +1,409 @@ +/** + * bookmarks.c + * Implementation of directory bookmarks functionality + */ + +#include "bookmarks.h" +#include +#include + +// Global variables for bookmark storage +BookmarkEntry *bookmarks = NULL; +int bookmark_count = 0; +int bookmark_capacity = 0; + +// Path to the bookmarks file +char bookmarks_file_path[PATH_MAX]; + +/** + * Initialize the bookmark system + */ +void init_bookmarks(void) { + // Set initial capacity + bookmark_capacity = 10; + bookmarks = + (BookmarkEntry *)malloc(bookmark_capacity * sizeof(BookmarkEntry)); + + if (!bookmarks) { + fprintf(stderr, "lsh: allocation error in init_bookmarks\n"); + return; + } + + // Determine bookmarks file location - in user's home directory + char *home_dir = getenv("HOME"); + if (home_dir) { + snprintf(bookmarks_file_path, PATH_MAX, "%s/.lsh_bookmarks", home_dir); + } else { + // Fallback to current directory if HOME not available + strcpy(bookmarks_file_path, ".lsh_bookmarks"); + } + + // Load bookmarks from file + load_bookmarks(); +} + +/** + * Clean up the bookmark system + */ +void cleanup_bookmarks(void) { + if (!bookmarks) + return; + + // Free all bookmark entries + for (int i = 0; i < bookmark_count; i++) { + free(bookmarks[i].name); + free(bookmarks[i].path); + } + + // Free the array + free(bookmarks); + bookmarks = NULL; + bookmark_count = 0; + bookmark_capacity = 0; +} + +/** + * Shutdown the bookmark system + */ +void shutdown_bookmarks(void) { + // Save bookmarks to file + save_bookmarks(); + + // Clean up + cleanup_bookmarks(); +} + +/** + * Load bookmarks from file + */ +int load_bookmarks(void) { + FILE *fp = fopen(bookmarks_file_path, "r"); + if (!fp) { + return 0; // File doesn't exist or can't be opened + } + + char line[LSH_RL_BUFSIZE]; + char name[LSH_RL_BUFSIZE / 2]; + char path[LSH_RL_BUFSIZE / 2]; + + while (fgets(line, sizeof(line), fp)) { + // Skip comments and empty lines + if (line[0] == '#' || line[0] == '\n') { + continue; + } + + // Try to parse using tab as delimiter first + char *tab = strchr(line, '\t'); + if (tab) { + // Split at tab + *tab = '\0'; + strncpy(name, line, sizeof(name) - 1); + name[sizeof(name) - 1] = '\0'; + strncpy(path, tab + 1, sizeof(path) - 1); + path[sizeof(path) - 1] = '\0'; + + // Remove newline if present + char *newline = strchr(path, '\n'); + if (newline) { + *newline = '\0'; + } + + add_bookmark(name, path); + } else { + // Parse in name=path format as fallback + if (sscanf(line, "%[^=]=%s", name, path) == 2) { + add_bookmark(name, path); + } + } + } + + fclose(fp); + return 1; +} + +/** + * Save bookmarks to file + */ +int save_bookmarks(void) { + FILE *fp = fopen(bookmarks_file_path, "w"); + if (!fp) { + fprintf(stderr, "lsh: error saving bookmarks to %s\n", bookmarks_file_path); + return 0; + } + + // Write file header + time_t t = time(NULL); + struct tm *tm_info = localtime(&t); + char timestamp[26]; + strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", tm_info); + + fprintf(fp, "# LSH Bookmarks - Last updated: %s\n\n", timestamp); + + // Write each bookmark + for (int i = 0; i < bookmark_count; i++) { + fprintf(fp, "%s\t%s\n", bookmarks[i].name, bookmarks[i].path); + } + + fclose(fp); + return 1; +} + +/** + * Add a new bookmark + */ +int add_bookmark(const char *name, const char *path) { + if (!name || !path) { + return 0; + } + + // Check if bookmark already exists + for (int i = 0; i < bookmark_count; i++) { + if (strcmp(bookmarks[i].name, name) == 0) { + // Update existing bookmark + free(bookmarks[i].path); + bookmarks[i].path = strdup(path); + return 1; + } + } + + // Check if we need to expand the array + if (bookmark_count >= bookmark_capacity) { + bookmark_capacity *= 2; + BookmarkEntry *new_bookmarks = (BookmarkEntry *)realloc( + bookmarks, bookmark_capacity * sizeof(BookmarkEntry)); + if (!new_bookmarks) { + fprintf(stderr, "lsh: allocation error in add_bookmark\n"); + return 0; + } + bookmarks = new_bookmarks; + } + + // Add new bookmark + bookmarks[bookmark_count].name = strdup(name); + bookmarks[bookmark_count].path = strdup(path); + bookmark_count++; + + return 1; +} + +/** + * Remove a bookmark + */ +int remove_bookmark(const char *name) { + if (!name) { + return 0; + } + + for (int i = 0; i < bookmark_count; i++) { + if (strcmp(bookmarks[i].name, name) == 0) { + // Free memory for this bookmark + free(bookmarks[i].name); + free(bookmarks[i].path); + + // Shift remaining bookmarks down + for (int j = i; j < bookmark_count - 1; j++) { + bookmarks[j] = bookmarks[j + 1]; + } + + bookmark_count--; + return 1; + } + } + + return 0; // Bookmark not found +} + +/** + * Find a bookmark by name + */ +BookmarkEntry *find_bookmark(const char *name) { + for (int i = 0; i < bookmark_count; i++) { + if (strcmp(bookmarks[i].name, name) == 0) { + return &bookmarks[i]; + } + } + return NULL; +} + +/** + * Command handler for the "bookmark" command + */ +int lsh_bookmark(char **args) { + char cwd[PATH_MAX]; + + // No arguments - add bookmark for current directory + if (args[1] == NULL) { + printf("Usage: bookmark [path]\n"); + printf("If path is omitted, the current directory is used.\n"); + return 1; + } + + // Get current working directory if no path is specified + if (args[2] == NULL) { + if (getcwd(cwd, sizeof(cwd)) == NULL) { + perror("lsh: getcwd"); + return 1; + } + add_bookmark(args[1], cwd); + printf("Bookmark added: %s -> %s\n", args[1], cwd); + } else { + add_bookmark(args[1], args[2]); + printf("Bookmark added: %s -> %s\n", args[1], args[2]); + } + + // Save bookmarks to file + save_bookmarks(); + + return 1; +} + +/** + * Command handler for the "bookmarks" command + */ +int lsh_bookmarks(char **args) { + if (bookmark_count == 0) { + printf("No bookmarks defined.\n"); + printf("Use 'bookmark [path]' to add a bookmark.\n"); + return 1; + } + + // Check if we should use a pager + if (bookmark_count > 20) { + // Check for neovim first + FILE *test_nvim = popen("which nvim 2>/dev/null", "r"); + if (test_nvim) { + char buffer[128]; + if (fgets(buffer, sizeof(buffer), test_nvim) != NULL) { + pclose(test_nvim); + FILE *pager = popen("nvim -R -c 'set nonumber' -", "w"); + if (pager) { + fprintf(pager, "LSH Bookmarks:\n\n"); + for (int i = 0; i < bookmark_count; i++) { + fprintf(pager, " %s -> %s\n", bookmarks[i].name, bookmarks[i].path); + } + pclose(pager); + return 1; + } + } + pclose(test_nvim); + + // Try vim + FILE *test_vim = popen("which vim 2>/dev/null", "r"); + if (test_vim) { + char buffer[128]; + if (fgets(buffer, sizeof(buffer), test_vim) != NULL) { + pclose(test_vim); + FILE *pager = popen("vim -R -c 'set nonumber' -", "w"); + if (pager) { + fprintf(pager, "LSH Bookmarks:\n\n"); + for (int i = 0; i < bookmark_count; i++) { + fprintf(pager, " %s -> %s\n", bookmarks[i].name, bookmarks[i].path); + } + pclose(pager); + return 1; + } + } + pclose(test_vim); + } + } + } + + // Simple output if no pager available or bookmark count is small + printf("LSH Bookmarks:\n\n"); + + // Use ANSI escape codes for colored output + for (int i = 0; i < bookmark_count; i++) { + printf(" " ANSI_COLOR_GREEN "%s" ANSI_COLOR_RESET " -> %s\n", + bookmarks[i].name, bookmarks[i].path); + } + + return 1; +} + +/** + * Command handler for the "goto" command + */ +int lsh_goto(char **args) { + if (args[1] == NULL) { + printf("Usage: goto \n"); + return 1; + } + + BookmarkEntry *bookmark = find_bookmark(args[1]); + if (bookmark) { + if (chdir(bookmark->path) != 0) { + perror("lsh: chdir"); + return 1; + } + printf("Changed directory to: %s\n", bookmark->path); + } else { + printf("Bookmark '%s' not found.\n", args[1]); + } + + return 1; +} + +/** + * Command handler for the "unbookmark" command + */ +int lsh_unbookmark(char **args) { + if (args[1] == NULL) { + printf("Usage: unbookmark \n"); + return 1; + } + + if (remove_bookmark(args[1])) { + printf("Bookmark '%s' removed.\n", args[1]); + save_bookmarks(); + } else { + printf("Bookmark '%s' not found.\n", args[1]); + } + + return 1; +} + +/** + * Get bookmark names for tab completion + */ +char **get_bookmark_names(int *count) { + if (bookmark_count == 0 || !count) { + *count = 0; + return NULL; + } + + char **names = (char **)malloc(bookmark_count * sizeof(char *)); + if (!names) { + *count = 0; + return NULL; + } + + for (int i = 0; i < bookmark_count; i++) { + names[i] = strdup(bookmarks[i].name); + } + + *count = bookmark_count; + return names; +} + +/** + * Find a matching bookmark by partial name + */ +char *find_matching_bookmark(const char *partial_name) { + if (!partial_name || strlen(partial_name) == 0) { + return NULL; + } + + // If only one bookmark exists, return it if there's any match + if (bookmark_count == 1) { + return strdup(bookmarks[0].name); + } + + // Look for partial matches + for (int i = 0; i < bookmark_count; i++) { + if (strncasecmp(bookmarks[i].name, partial_name, strlen(partial_name)) == 0) { + return strdup(bookmarks[i].name); + } + } + + return NULL; +} \ No newline at end of file diff --git a/bookmarks.h b/bookmarks.h new file mode 100644 index 0000000..715e5fe --- /dev/null +++ b/bookmarks.h @@ -0,0 +1,57 @@ +/** + * bookmarks.h + * Functions for managing directory bookmarks + */ + +#ifndef BOOKMARKS_H +#define BOOKMARKS_H + +#include "common.h" + +// Structure to represent a bookmark +typedef struct { + char *name; // Bookmark name + char *path; // Directory path +} BookmarkEntry; + +// Initialize bookmark system +void init_bookmarks(void); + +// Clean up bookmark system +void cleanup_bookmarks(void); + +// Shutdown the bookmark system +void shutdown_bookmarks(void); + +// Load bookmarks from file +int load_bookmarks(void); + +// Save bookmarks to file +int save_bookmarks(void); + +// Add a new bookmark +int add_bookmark(const char *name, const char *path); + +// Remove a bookmark by name +int remove_bookmark(const char *name); + +// Find a bookmark by name +BookmarkEntry *find_bookmark(const char *name); + +// Command handlers +int lsh_bookmark(char **args); // Add a bookmark +int lsh_bookmarks(char **args); // List all bookmarks +int lsh_goto(char **args); // Jump to a bookmark +int lsh_unbookmark(char **args); // Remove a bookmark + +// Get bookmarked directories for tab completion +char **get_bookmark_names(int *count); + +// Find a matching bookmark by partial name +char *find_matching_bookmark(const char *partial_name); + +// Global bookmarks array +extern BookmarkEntry *bookmarks; +extern int bookmark_count; + +#endif // BOOKMARKS_H \ No newline at end of file diff --git a/bookmarks.o b/bookmarks.o new file mode 100644 index 0000000000000000000000000000000000000000..8e5aa14f586a1450bef1e7ed797b5f8bf944943a GIT binary patch literal 22640 zcmbt+30#fK|Nqm12t}dLb?By~Qc^0F7U>|#5((v0r$wDpI;XOfq>iMbYspe5WV>!I z*OI-m)U|{wM3xXmmTbw|f982+PSf1Z_jg~f|Gb>@JoBFSyg#4$%sex5p65xTo5xsX zB_#$YCB~6y&0&;bqNcQ-JF%xuj1JR>@#d#J<0rq;Eb9QlF5r{Sp7A&GOKMd4X=U{g z=cjQXDw7q*81T_~TFD6`z&Hbq@-sOas?{K(0DhWVGe0?@nUR|C)4^$4iJVY+hS4Mi zilAB6cEcckky(T!)IT6H68ljU87>k;hfAs(hvE{B)p#n#r|^Dt1!C<;iZ}l{kv6+xPfG*bJ`C#SmI*@2o*7i}R3m zmi@|_!?~RF%3O_Mg81pG21cMZ43kB%JTw>OXSg$DRi9g0_{pc?fzgmTfY`I~dJzuJ zG>*y|zqPd3>uaRw6WJ~rDcT^*&tyx_bY|_y1#37#cwjVAw!^}78O&XTRWhL|W{?Clp&3DNnPd?iQ(P&-7R!a4v-&%mLEHTY?=dd>lOV5D7u8a!i-uZLpD zI6v(+uG26c`o$Klhkl`k@iVP}FjQ_GLCMX^G5z_OiiDK1`04A}h@#jqs)TD`49WKX z1p4V*)KO;_fhd4Rdp8I1hibFEChfrXseBZA{rCQKD+X6ZF%vTkkEqOEY$GzeaczOY zZfy?N)mK2#Sy;?k1w*EYp9wyAET*}Y1MkWKcAcMggU<<`=?nOBN~Sj$`@nSjR?6HC zL-mFU$ftDg!{jx?S8E^FQTYv*wMK9=_1VmTGePe%N-gerbo%ykf`Dn{A~ z9Ii7lUAR!hfxaknt7Y9ykh@h&x(mAs)R&JQFoR8MpV@k~|GPZ1KWrWdD86o7)!1?H z;uEl)>{cspV68@mw56pbo$W?6W0b~6a%W1#+-%C_@I+gR%n?rV)7tKj-J0cH->i|*8+1L}8*L+lSD`U&9co>L=qSYWZjafZ-Rc(f=^$w;=@kzyqiLt> z-?p^S6A+kG0m@G&gUUIQ#IT-&R2C6s%@Bj?_!Bu8Ku-yX#tlbHyOm-gfL28(R z2kv?Zk(X!dy78|f*nzB#_Lgu~8((B>CO!xAQG>WqRt>u(oeR-_XlV`CQg{F@)nhBK zXTeNa6u6ERhLYv{2Ltt-0eEN)B@6z~P?ke}+fYJCK`7}W_F91Sc0&o-@=(GI8_Igf zZxhNaU>}6C-Ij8zN15yjsKxp@Ro>+gBK?FjDm#|bGr1x(*_N{tEit@XFYRPjSMDRM z7QgNPx*U^VaSIS!09)s{_U9t5X{|)uk@6oXVA}(Jprp61CbD8_Z}~OJwVrjTf#1q( zw=LlJ3*k{(yBt0>jIZ*zJu99#?$%j;04yrC~1K!P(={;@x%!m(JxgyWWC! zz<#ctpV_}htFlU)4OskfwCw?&rGd)ce3j~={@ZKC2sSwK-%Max7$|RL`#(kLRel3n<-reOJDwmS zA~H}Q4T}`>gwfHF(Y!D*_!lOHKasf~#$6cxq={~ffn*r|>5P6bM>7Vq{2b;u7)Y2n z7)Mr*6OjmF!^9yxxdu-f$up32VGL%P8i-5{f_MgeJA;XK22)`@eV)fuKF?;d0`S>q$o@ZY?<(+p+a6@OmwtREae4-MGFI^kK@4`7 z2h4JA@=P7sR(eLttx9-7!r(A5tP30x@(giE+PY&10|az<0(ng{CN4BAFq9{b4HNN( zI}QsH#tsw5L_{zwU^<0o8pt!02&Fu6q&P+tAdEKTnKEqxX$Qi_0}f%gI6Ybp=Kq@- z5bHO~a=6Gq(r=bIsKhlEg*hY=w7?#>&Yz7n7p}li5J<)~R3Hu!1`$D(MzUSo8b?C| zi6Ll>louQsBMvg-Ivey8vJfN2>i@DM?+R8TS}2N)1rf&rU?FDH_O9F!=NIIPrqA-o zb<^H@_ioG4Z*M#J(a|APFm{gZooymHMv_W4Y+S6!~9WsA6BTjRAa70*V6ROBXR z$0b}exj1L=wuUQ1TQ>1kqqY6=w_Tob`NDiXrwOIguSt@7&g{DWux7rNOCLiI^<(40 zbdBd5JqWEmw>~NNcV^+ zXUtvS$-^vZk?J_*IDMZnbFG#cD~D@VY8G{J)=OI4qf)C#qr_Lan_Az_`(3Yl)GSdI zss3V8Z6@~8}KUd)2gR$de7_Ie^}&*T(xE9 zNk+<>waVOUv{nqv%b)*5ZHj77>3G#OYQ43LT%4ZP?)*O1($h0cd1YZ>LE_)fzV2*T zyjvP0?rP|kWYf*;$UhTT+>zbOUp(W>%pvJh#~!?t8qsUpIJXfmI`7)L@@+x=tfcKd z{VddTRSaTd!+hST*ey12_8T|qmx|A&k)wuZr1|cYoinSKmAOCq?7Y=y$Q{4ePV*jh z5!^3yIWqEBuLPaSI^~$LHJv?s2TeZew`!o|-t^MmJC^*_{CZ!mLB7q$xBgzq#WOY! z4;&zSVt(~m&-t36>O~jo>vUp&FSyHJ-1VllZwG_?ArED<-uxx~rDl-fbql3)?pt>l z?3kjG7(ZkIi$K`+YJ#Z@SpEr&N54;eh*;!1OTd2Eb!d{6qOZ}*sN%sQ|_jLnHEdQ9kWdHP^ z0l$_%4W8RsSY3Lrp~I2Ei>s=qc^ZA&Kd67rn*uKK zE6>{2JSzM$t5$bp{l043B^$rm&RY{-u=enW@d2-Qt@tGC@o3|UKYt%|`@eCh+M!<&A*C>0G&f0NfNtDV{7{O93%Evr}g7X>e=uAKMzPygh1Zbx4% zn`i7{^+%5j)^if9s-G==9e&}qD8uw#(fS`*Bla5I`EA+k0UKwZt)K0l?NvC|B_`$e zX4?hse{36TzPKXZcyPj5U;W0fHf~xEcD-M%T^l+4OU|=vdwyJDsvqBYF)5=eIbxEk z*vIz1ez{fO)RQxRaVWVnTW!seO;_}sXEg2YVPmmdCc%np0MTMsSuNMOCFZ}(|5$nin%(GF4v}L*@rAU zSU&H2Y9}+prU5Op-Gb0OjOX7~;KwFRI1lFI$<sWicDVPMZ~dZqtxY6=8Lx}C6XSqk$ddhZh zHK@thQ@N_2^_owGH>FJvpKcpJ^V6R1>8olVpL}{dVPslu{@QW#EEgTh4_#dHMY6u? z!aloQ_r!0znqPJ}DVx8e=*hU^${u!|HrP5!cf2`Vx46YDBWKP+=iP$fmsbk)eT}aU z+GOY%VXq?IoTtJ&m@qT-*yfag!UUV?FZ=X+zad6)r<3~qSuQnNy*Gbv_-ELUS)Y0p zZgl)Z7SZi&jdetg;OxS)va*(eIj@IVuNigP1O$zXof;cJ{Pm{>K5Ki_0@)4>$5ma^ zJ4Z(~Pv?M+Jnk#mJt^4_G1IO^_H)yIxaGyMQ70ch*m*SWb>+m|5#5IDk?!yU zTwX2drDEGNC2P^4wJIAf4T;*BOe zdho#;N6r0wdYcFngfp{6)rsx{`{hi!H+lEBmY*qe`bZ=PzC|RIq{pAzo>=!Y z&iU&5^LIlIMd&YC`Z6%(rS<(eHhOuc(B=-go#pc!BC& z=OJ#}H#=z+IQ$j??pZ9vri-Ow>jNk@6>P5cwA>!c<<$=;y~jbNj^gd+L<>x?$fQE5R>7wC2G^L zJ>90=pJghNCcUhiDNAiE^Z2s$-k=jbU7Dt*p6HY@hd=)}CqJ!~KX$Kpn>W7uG1(V~ z%4zEAuSUD93k!btRCoTMA5(4I_XHJLB=rmz7R?!BpL1MKHMPiN%ZZ@kl1>M0Z`*#}k)SDzt{ykw;oQJ2~ozxYhpFMmb z74DW~|2eE~lI_c}DkaUCN2X@p>c0I<(!(uEi9(;#`Pq}3wJIWaI<0YCRjM@LRDw#K zYIXmS3%h1SO%z7F3^;PdI_&)-$@T*u{r0&xjt+h25J z9n8`Xs8j8{R+eyh%9S3MuV!1{*&P()+IwrB$2FP8`-g+=bt7GV%4$0NY9&hk_*wUf zM?d{@Z#^_dH73@L58qi*s#CGTw_Lc()ugGWc8~P&CyxP(qb$Yxv3pX7CH+$HLnV1e z-vfg1lTn>7XZ0wYa((N)vLjn&Fb&;)y;ii^%CanPl#__RI`4Azob2N0mEL`GADusS zZ%ojWhRVomyAt`=49|V@{r&CcdAr;?+?9Iu8TX4c;-%rU0-xcFd^f!;4Gf<)*z@2z zfh_m8h5MfDo|$L3?y%;^8Q(PG(k@$rOApU)Q~q_G3D=c~tIfME|6;Txski9*k%s&Y z-5z+&t@0eDzH-c6m!R=kwLvd#u3o2C<~A(NbaL&r)n{`L?SARBw?22@+$Uptxs0%z zHhR#WW223C95uexbw~G8Dwn$6)2f`@ZT_X}f!^PAGxggkbu+dLF+d576 zX}3d)#v~cLUWplP%Rf=pwbul1_tBS}hrhUTIVSXo?bz2b&W*JPge$cZSEuY>_qFhc z$F%rKp`+foA9XmcW~RSv#FTx(&g1G{#)KLtHEMrP)sBuHS85vURnckZ0@>1_lCIU$ zD?3z0&pw{_t<)wV?fI9P>jOquJY0M1iqnkKu?EN2Z5ke;c9U?hR5IxCUyR&GKr=cj`!F8&BRzoRg?u`+RlOU|=bk1p(z{qt)|aqjh-rZd$KUZ1)D`pwo8IR`ychB@>Mj%@b+>$Ts{goINI= z&TiJ&KjAGNulP6{o#6a}-1U>HyDW3k{FEv+clnyMEH6H)uSxd&U! zYR5wyq?^z=T&_}~1R2nFE-VDeqfNOxTh0UcDOd>7F0$M$Sw$t6rLY<`EQ4YCk{p#@ zavL}>;gE-YP!5*2fd}h>Bx+MXR9@c+m9GX*D&+N5R;u7O%thtwT|l{hsa$_4D$jvN zG91gQcQc2rRy z$f__M{|&Nu+bta?sW9sJw9Qe4K{qwppisX%g>YFF=HGk7#h|DMd{F@<>;ZgZ0OB~0 z8E~9I99zaXxW&cdJaA+ae7XaY3;6UT;=^7W0GkXxhyu=9lMgs;5BFDq2P?ou3h-Ef zLw}Z{E@Q7HfXNV!{bR3DfNcPu_WXg@8q|qII_xzIumcF63dc7{?6nAvXTYaDo%0It z%L?$D0Ec$Bp}@1(GQesS@EaB2O$zWI3h?fro$dMms{*{Y0-UD+AEE#^SAdUHfR6?^ zjE@_-#MpTZv}qE;{X2mSNbLLtj&l%x3E}L#1@L(a^kILu7l&8{xP}5e0pQTjk?;j7 zkl6VU9Mcu>e^Y>OL^>DI1dWDFY7Q2JC6eXQG^?zse_$A0sc3_8xdX% zFqmo-=+`O08GQd%ViqVr_YVX&d!Ivv5Z6<6&)s)1~U_47f5Jrf%K<`17nEZimI(4NKJcwcj5|O9kRaXS;1Z6Na5&U049_x3220_C76fVp3LO48-{umH^^15?Sfcp?QbOFBq2$K-u z@IdNE5`6MHT}trD{@q02JfMZ!RY~ZOetsbMaPGwXp9=VW;16+-U@8H&Wk* z;KMgsvA!3da1%mjCZ#hB zt-At(Z%Xjf37lNl_E9>ckj^oJ5ASJU|7!@G)ai(Rzu`Dw9W8{zIFLFz1WxWlEC`%O z*!3m!$@mKi9L@vY$bS)`L&jf9@gopFUI9OY;FET92^`wB2OpSrQFt!WFC_HM0T0LX zA%TfgM{P%7qY8?a2S8m?r4gC4e{LxJ~@B-5`1`y{f|+A zXA?M#5B!}B(+-3~e+GgN*7=j*lW{I1_+%Vv6ySA)4%sj7DEt-j=L?}j#%Bn00wm}s z*)PrnPWr<~IF3K=mnjsk3<)6l5;~;al@uTM%Nl}D_Dcc5hfTrpELMO&CUCM}-Vpj^ zzkDP3@D%I!gqs79V0_3p3{`*+M>vj;9*TnM4XPqr&m0WKqO*e+9~zlP8! z=bvo^pKMn#!RHbFJR|r}-v#NvCitZPUEt;$Bp9C|;Dg&`K;V`HZjNvqA3vmTL-0)r z{$z?DhWLI2pKNao#ZN~3WeWKFDgI8xKTPn+_Er$M5#eVYrE?MKd?fg!pI-=^To*LE z15uD*br^r_zaGM2oJpOL1fT5R*$VJ^gbsPXC7a-r`apI5rRWqA+0`U2g0>1c<|F91SU$WsKQxj*qr%EHaG1 zq21Xi??B-lkk|wYAB)xt{Ab_Te`SQvr1^m_*0}Krf__}DTcyb zkp3bH$8BCt;YujZYbbmY!uM17X{3LY!oMT`|EBP>C|^P0PY@sPi*ej0q4w5OeE1t1 zrcc~KK2G5C6_{|mv5q?OUjvn69RE)4PvM5hAAG+K^UomMn&RW<0g!V1(GN#XF%1z{RP;X6=%GKC*N{`gV& zG=zs!_)3&tK;g$Yv&=dQ$Nim8;n|3f?|{&tGAxK{(7pEu7vF zI9wlb`bz2ij`AH*zd;?m*1@(KIYZe0V+ij;;nR^mzE6nxtB{|r6yFNz_)&Nl zBmD~$Zh~~~Q@AeDsY5ty4wS&p&++|0+^*M1ryJV9VE#z7 zzcfWS=DQ%i4aLXL?I%%uB*XYo_!bl&5v8*d?bp{({41zkTPQw$kKi!H*G1#tJcXAc zyVock{QkmoijQ?ZQFsK3LkG0s#_`EO{e|y0%HxSP*M<}y>yJb@=5IoL4~m}#2_Vg; z_+^MMqWJ%y_9jrcjFVw9DV+wSvz_86BK{$YKLIuzq?-gE4m~`FRuMQn#s1V&I@V~C z{zCDw-Ok7_9G`5&H>Ge#WY`bkxL@4RcnGEV_`RD%ijVtcD}~3Sc;QNrcz4(2iZYbWkU0A;#!ZAMpUH>)|UX5@cN=Fy9D}dtT_q-NT zd~7$B!twgPp3*5t*Y7b37omPBr*uXlyo$m@k+s|Qnf0LmLvIR1TZM&UbAemI4nLV5iB0o(l>;m#EQ z7RryM@W&`Wfx=&+ycdPPM|r%@!gjwQ+?V3x_i6ko9N*svqHz3sHjKiJ&^QrOxH-Zl z6mEy`1r&~d&nHkgeou87h2!T+83>26Xy~&D58)6aaVHAL<905Eyxl6%AfAj0SIWa=OA$|KMowzc8Q<`u{xeKz$fOJWpXc zCv-ypIV1`PR>2>g8n>!NKD_`fc>1m`t~qh$%9V4sgS+;W6F zq3xRh7-}l2&%+Zf(&3>aKEP*BP?NmoU>UZL?>|BeChR|#!7 zUEdZIwHH4=y0Ki2{D<*_eT2>6_>Bixd-g*S!I=set`DlQX%6_NC@j7gzAOfkId_nM z(_9}=(w_gCo?I1NANmj1Gi)FG9|1606V|+o?Dv5gBGKF=P{v|d7;zg>eIYe4C>j$F z`0e@cg#2$t2BH6OiO2P^|Cs=T6!;&8lF3Jp%N?W!7N#LtW+R}rS6`FI)xXFc`2ITVKP~XV^>P2TXB*a3(}&*-!$ pqtNx?n5KppKp1AO5qn@hQ2tX{_8sZ=>aUp0)qlzz +#include +#include +#include +#include +#include +#include +#include +#include + +// History variables +HistoryEntry command_history[HISTORY_SIZE]; +int history_count = 0; +int history_index = 0; + +// String array of built-in command names +char *builtin_str[] = { + "cd", "help", "exit", "dir", "clear", + "mkdir", "rmdir", "del", "touch", "pwd", + "cat", "history", "copy", "move", "paste", + "ps", "news", "alias", "unalias", "aliases", + "bookmark", "bookmarks", "goto", "unbookmark", "focus_timer", + "weather", "grep", "grep-text", "ripgrep", "fzf", + "clip", "echo", "theme", "loc", "git_status", + "gg"}; + +// Array of function pointers to built-in command implementations +int (*builtin_func[])(char **) = { + &lsh_cd, &lsh_help, &lsh_exit, &lsh_dir, &lsh_clear, + &lsh_mkdir, &lsh_rmdir, &lsh_del, &lsh_touch, &lsh_pwd, + &lsh_cat, &lsh_history, &lsh_copy, &lsh_move, &lsh_paste, + &lsh_ps, &lsh_news, &lsh_alias, &lsh_unalias, &lsh_aliases, + &lsh_bookmark, &lsh_bookmarks, &lsh_goto, &lsh_unbookmark, &lsh_focus_timer, + &lsh_weather, &lsh_grep, &lsh_actual_grep, &lsh_ripgrep, &lsh_fzf_native, + &lsh_clip, &lsh_echo, &lsh_theme, &lsh_loc, &lsh_git_status, + &lsh_gg}; + +/** + * Set the console text color + */ +void set_color(int color) { + switch(color) { + case 0: printf(ANSI_COLOR_RESET); break; + case 1: printf(ANSI_COLOR_RED); break; + case 2: printf(ANSI_COLOR_GREEN); break; + case 3: printf(ANSI_COLOR_YELLOW); break; + case 4: printf(ANSI_COLOR_BLUE); break; + case 5: printf(ANSI_COLOR_MAGENTA); break; + case 6: printf(ANSI_COLOR_CYAN); break; + case 7: printf(ANSI_COLOR_WHITE); break; + default: printf(ANSI_COLOR_RESET); + } +} + +/** + * Reset console color to default + */ +void reset_color() { + printf(ANSI_COLOR_RESET); +} + +/** + * Get the number of built-in commands + */ +int lsh_num_builtins() { return sizeof(builtin_str) / sizeof(char *); } + +/** + * Add a command to the history + */ +void lsh_add_to_history(const char *command) { + // Don't add empty commands or duplicates of the last command + if (!command || *command == '\0' || + (history_count > 0 && + strcmp(command_history[history_index - 1].command, command) == 0)) { + return; + } + + // Free the oldest entry if we're overwriting it + if (history_count == HISTORY_SIZE) { + free(command_history[history_index].command); + } else { + history_count++; + } + + // Add the new command + command_history[history_index].command = strdup(command); + command_history[history_index].timestamp = time(NULL); + + // Update the index + history_index = (history_index + 1) % HISTORY_SIZE; +} + +/** + * Built-in command: cd + * Changes the current directory + */ +int lsh_cd(char **args) { + if (args[1] == NULL) { + // No argument provided, change to home directory + char *home_dir = getenv("HOME"); + if (home_dir == NULL) { + fprintf(stderr, "lsh: HOME environment variable not set\n"); + return 1; + } + if (chdir(home_dir) != 0) { + perror("lsh: cd"); + } + } else { + if (chdir(args[1]) != 0) { + perror("lsh: cd"); + } + } + return 1; +} + +/** + * Built-in command: help + * Displays help information + */ +int lsh_help(char **args) { + printf("LSH Shell - A lightweight shell with modern features\n"); + printf("Type a command and press Enter to execute it.\n"); + printf("The following built-in commands are available:\n\n"); + + // Sort commands alphabetically + char *sorted_commands[lsh_num_builtins()]; + for (int i = 0; i < lsh_num_builtins(); i++) { + sorted_commands[i] = builtin_str[i]; + } + + for (int i = 0; i < lsh_num_builtins() - 1; i++) { + for (int j = i + 1; j < lsh_num_builtins(); j++) { + if (strcmp(sorted_commands[i], sorted_commands[j]) > 0) { + char *temp = sorted_commands[i]; + sorted_commands[i] = sorted_commands[j]; + sorted_commands[j] = temp; + } + } + } + + // Print commands in columns + int columns = 4; + int rows = (lsh_num_builtins() + columns - 1) / columns; + for (int i = 0; i < rows; i++) { + for (int j = 0; j < columns; j++) { + int index = j * rows + i; + if (index < lsh_num_builtins()) { + printf("%-15s", sorted_commands[index]); + } + } + printf("\n"); + } + + printf("\nFor more information on specific commands, type 'help '\n"); + printf("Use tab completion for commands and file paths\n"); + printf("Use arrow keys to navigate command history\n"); + printf("Type a partial command followed by '?' for suggestions\n"); + + return 1; +} + +/** + * Built-in command: exit + * Exits the shell + */ +int lsh_exit(char **args) { return 0; } + +/** + * Built-in command: dir + * Lists files in the current directory + */ +int lsh_dir(char **args) { + DIR *dir; + struct dirent *entry; + struct stat file_stat; + char cwd[PATH_MAX]; + char file_path[PATH_MAX]; + int count = 0; + int detailed = 0; + + // Check if we should show detailed listing + if (args[1] != NULL && (strcmp(args[1], "-l") == 0 || strcmp(args[1], "--long") == 0)) { + detailed = 1; + } + + if (getcwd(cwd, sizeof(cwd)) == NULL) { + perror("lsh: getcwd"); + return 1; + } + + dir = opendir(cwd); + if (dir == NULL) { + perror("lsh: opendir"); + return 1; + } + + if (detailed) { + printf("Mode Size Modified Name\n"); + printf("----------------------------------------------------\n"); + } + + // First collect all entries + typedef struct { + char name[256]; + struct stat stat; + int is_dir; + } DirEntry; + + DirEntry *entries = malloc(1000 * sizeof(DirEntry)); // Arbitrary limit + int entry_count = 0; + + while ((entry = readdir(dir)) != NULL && entry_count < 1000) { + // Skip . and .. entries + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { + continue; + } + + snprintf(file_path, sizeof(file_path), "%s/%s", cwd, entry->d_name); + if (stat(file_path, &file_stat) == 0) { + strcpy(entries[entry_count].name, entry->d_name); + entries[entry_count].stat = file_stat; + entries[entry_count].is_dir = S_ISDIR(file_stat.st_mode); + entry_count++; + } + } + + closedir(dir); + + // Sort entries - directories first then files + for (int i = 0; i < entry_count - 1; i++) { + for (int j = i + 1; j < entry_count; j++) { + if (entries[i].is_dir < entries[j].is_dir || + (entries[i].is_dir == entries[j].is_dir && + strcmp(entries[i].name, entries[j].name) > 0)) { + DirEntry temp = entries[i]; + entries[i] = entries[j]; + entries[j] = temp; + } + } + } + + // Display entries + for (int i = 0; i < entry_count; i++) { + if (detailed) { + // Format mode (simplified) + char mode[11] = "----------"; + if (entries[i].is_dir) mode[0] = 'd'; + if (entries[i].stat.st_mode & S_IRUSR) mode[1] = 'r'; + if (entries[i].stat.st_mode & S_IWUSR) mode[2] = 'w'; + if (entries[i].stat.st_mode & S_IXUSR) mode[3] = 'x'; + if (entries[i].stat.st_mode & S_IRGRP) mode[4] = 'r'; + if (entries[i].stat.st_mode & S_IWGRP) mode[5] = 'w'; + if (entries[i].stat.st_mode & S_IXGRP) mode[6] = 'x'; + if (entries[i].stat.st_mode & S_IROTH) mode[7] = 'r'; + if (entries[i].stat.st_mode & S_IWOTH) mode[8] = 'w'; + if (entries[i].stat.st_mode & S_IXOTH) mode[9] = 'x'; + + // Format size + char size_str[20]; + if (entries[i].stat.st_size < 1024) { + snprintf(size_str, sizeof(size_str), "%d B", (int)entries[i].stat.st_size); + } else if (entries[i].stat.st_size < 1024 * 1024) { + snprintf(size_str, sizeof(size_str), "%.1f KB", + entries[i].stat.st_size / 1024.0); + } else { + snprintf(size_str, sizeof(size_str), "%.1f MB", + entries[i].stat.st_size / (1024.0 * 1024.0)); + } + + // Format time + char time_str[20]; + struct tm *tm_info = localtime(&entries[i].stat.st_mtime); + strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M", tm_info); + + // Print entry with colors + printf("%s %-10s %-17s ", mode, size_str, time_str); + + if (entries[i].is_dir) { + printf(ANSI_COLOR_BLUE "%s" ANSI_COLOR_RESET "\n", entries[i].name); + } else if (entries[i].stat.st_mode & S_IXUSR) { + printf(ANSI_COLOR_GREEN "%s" ANSI_COLOR_RESET "\n", entries[i].name); + } else { + printf("%s\n", entries[i].name); + } + } else { + count++; + if (entries[i].is_dir) { + printf(ANSI_COLOR_BLUE "%-20s" ANSI_COLOR_RESET, entries[i].name); + } else if (entries[i].stat.st_mode & S_IXUSR) { + printf(ANSI_COLOR_GREEN "%-20s" ANSI_COLOR_RESET, entries[i].name); + } else { + printf("%-20s", entries[i].name); + } + + if (count % 4 == 0) { + printf("\n"); + } + } + } + + free(entries); + + if (!detailed && count % 4 != 0) { + printf("\n"); + } + + return 1; +} + +/** + * Built-in command: clear + * Clears the screen + */ +int lsh_clear(char **args) { + printf(ANSI_CLEAR_SCREEN); + printf(ANSI_CURSOR_HOME); + return 1; +} + +/** + * Built-in command: mkdir + * Creates a new directory + */ +int lsh_mkdir(char **args) { + if (args[1] == NULL) { + fprintf(stderr, "lsh: expected argument to \"mkdir\"\n"); + } else { + if (mkdir(args[1], 0755) != 0) { + perror("lsh: mkdir"); + } + } + return 1; +} + +/** + * Built-in command: rmdir + * Removes a directory + */ +int lsh_rmdir(char **args) { + if (args[1] == NULL) { + fprintf(stderr, "lsh: expected argument to \"rmdir\"\n"); + } else { + if (rmdir(args[1]) != 0) { + perror("lsh: rmdir"); + } + } + return 1; +} + +/** + * Built-in command: del + * Deletes a file + */ +int lsh_del(char **args) { + if (args[1] == NULL) { + fprintf(stderr, "lsh: expected argument to \"del\"\n"); + } else { + if (unlink(args[1]) != 0) { + perror("lsh: del"); + } + } + return 1; +} + +/** + * Built-in command: touch + * Creates a new file or updates timestamp of existing file + */ +int lsh_touch(char **args) { + if (args[1] == NULL) { + fprintf(stderr, "lsh: expected argument to \"touch\"\n"); + } else { + int fd = open(args[1], O_CREAT | O_WRONLY | O_APPEND, 0644); + if (fd == -1) { + perror("lsh: touch"); + } else { + close(fd); + } + } + return 1; +} + +/** + * Built-in command: pwd + * Prints the current working directory + */ +int lsh_pwd(char **args) { + char cwd[PATH_MAX]; + if (getcwd(cwd, sizeof(cwd)) != NULL) { + printf("%s\n", cwd); + } else { + perror("lsh: getcwd"); + } + return 1; +} + +/** + * Built-in command: cat + * Displays the contents of a file + */ +int lsh_cat(char **args) { + if (args[1] == NULL) { + fprintf(stderr, "lsh: expected argument to \"cat\"\n"); + return 1; + } + + FILE *fp = fopen(args[1], "r"); + if (fp == NULL) { + perror("lsh: cat"); + return 1; + } + + char buffer[1024]; + while (fgets(buffer, sizeof(buffer), fp) != NULL) { + printf("%s", buffer); + } + + fclose(fp); + return 1; +} + +/** + * Built-in command: history + * Displays command history + */ +int lsh_history(char **args) { + char time_str[20]; + struct tm *tm_info; + + printf("Command History:\n"); + printf("----------------\n"); + + // Display history in chronological order + for (int i = 0; i < history_count; i++) { + int idx = (history_index - history_count + i + HISTORY_SIZE) % HISTORY_SIZE; + tm_info = localtime(&command_history[idx].timestamp); + strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", tm_info); + printf("%3d: [%s] %s\n", i + 1, time_str, command_history[idx].command); + } + + return 1; +} + +/** + * Built-in command: copy + * Copies a file + */ +int lsh_copy(char **args) { + if (args[1] == NULL || args[2] == NULL) { + fprintf(stderr, "lsh: expected source and destination arguments to \"copy\"\n"); + return 1; + } + + FILE *source = fopen(args[1], "rb"); + if (source == NULL) { + perror("lsh: copy (source)"); + return 1; + } + + FILE *dest = fopen(args[2], "wb"); + if (dest == NULL) { + fclose(source); + perror("lsh: copy (destination)"); + return 1; + } + + char buffer[4096]; + size_t bytes_read; + while ((bytes_read = fread(buffer, 1, sizeof(buffer), source)) > 0) { + fwrite(buffer, 1, bytes_read, dest); + } + + fclose(source); + fclose(dest); + printf("Copied %s to %s\n", args[1], args[2]); + return 1; +} + +/** + * Built-in command: move + * Moves a file + */ +int lsh_move(char **args) { + if (args[1] == NULL || args[2] == NULL) { + fprintf(stderr, "lsh: expected source and destination arguments to \"move\"\n"); + return 1; + } + + if (rename(args[1], args[2]) != 0) { + perror("lsh: move"); + return 1; + } + + printf("Moved %s to %s\n", args[1], args[2]); + return 1; +} + +/** + * Built-in command: paste + * Placeholder for paste functionality + */ +int lsh_paste(char **args) { + printf("Paste functionality not implemented yet\n"); + return 1; +} + +/** + * Built-in command: ps + * Lists running processes + */ +int lsh_ps(char **args) { + FILE *fp = popen("ps -ef", "r"); + if (fp == NULL) { + perror("lsh: ps"); + return 1; + } + + char buffer[1024]; + while (fgets(buffer, sizeof(buffer), fp) != NULL) { + printf("%s", buffer); + } + + pclose(fp); + return 1; +} + +/** + * Built-in command: news + * Placeholder for news functionality + */ +int lsh_news(char **args) { + printf("Fetching news feed...\n"); + printf("News functionality not fully implemented yet\n"); + return 1; +} + +/** + * Built-in command: clip + * Placeholder for clipboard functionality + */ +int lsh_clip(char **args) { + printf("Clipboard functionality not implemented yet\n"); + return 1; +} + +/** + * Built-in command: echo + * Echoes arguments to stdout + */ +int lsh_echo(char **args) { + if (args[1] == NULL) { + printf("\n"); + return 1; + } + + for (int i = 1; args[i] != NULL; i++) { + printf("%s", args[i]); + if (args[i + 1] != NULL) { + printf(" "); + } + } + printf("\n"); + return 1; +} + +/** + * Built-in command: loc + * Counts lines of code + */ +int lsh_loc(char **args) { + if (args[1] == NULL) { + fprintf(stderr, "lsh: expected file or directory argument to \"loc\"\n"); + return 1; + } + + struct stat st; + if (stat(args[1], &st) != 0) { + perror("lsh: loc"); + return 1; + } + + if (S_ISREG(st.st_mode)) { + // Count lines in a single file + FILE *file = fopen(args[1], "r"); + if (!file) { + perror("lsh: loc"); + return 1; + } + + int lines = 0, code_lines = 0, blank_lines = 0, comment_lines = 0; + char line[1024]; + int in_comment_block = 0; + + while (fgets(line, sizeof(line), file)) { + lines++; + char *trimmed = line; + while (*trimmed && isspace(*trimmed)) trimmed++; + + if (*trimmed == '\0') { + blank_lines++; + } else if (strncmp(trimmed, "//", 2) == 0) { + comment_lines++; + } else if (strncmp(trimmed, "/*", 2) == 0) { + comment_lines++; + in_comment_block = 1; + if (strstr(trimmed, "*/")) { + in_comment_block = 0; + } + } else if (in_comment_block) { + comment_lines++; + if (strstr(trimmed, "*/")) { + in_comment_block = 0; + } + } else { + code_lines++; + } + } + + fclose(file); + + printf("File: %s\n", args[1]); + printf("Total lines: %d\n", lines); + printf("Code lines: %d\n", code_lines); + printf("Comment lines: %d\n", comment_lines); + printf("Blank lines: %d\n", blank_lines); + + } else if (S_ISDIR(st.st_mode)) { + printf("Directory LOC counting not implemented yet\n"); + } else { + fprintf(stderr, "lsh: %s is not a file or directory\n", args[1]); + } + + return 1; +} + +/** + * Helper function to extract a string value from a JSON response + */ +char *extract_json_string(const char *json, const char *key) { + char search_key[100]; + sprintf(search_key, "\"%s\":", key); + + char *key_pos = strstr(json, search_key); + if (!key_pos) return NULL; + + key_pos += strlen(search_key); + + // Skip whitespace + while (*key_pos && isspace(*key_pos)) key_pos++; + + if (*key_pos != '"') return NULL; + + key_pos++; // Skip opening quote + + // Find closing quote + char *end = key_pos; + while (*end && *end != '"') { + if (*end == '\\' && *(end + 1)) { + end += 2; // Skip escaped character + } else { + end++; + } + } + + if (!*end) return NULL; + + // Allocate and copy the string value + int len = end - key_pos; + char *result = malloc(len + 1); + if (!result) return NULL; + + strncpy(result, key_pos, len); + result[len] = '\0'; + + return result; +} + +/** + * Built-in command: git_status + * Displays the Git status of the current repo + */ +int lsh_git_status(char **args) { + // Show current Git status + char *git_status = get_git_status(); + if (git_status) { + printf("Git Status: %s\n", git_status); + free(git_status); + } else { + printf("Not in a Git repository or Git not available\n"); + } + return 1; +} + +/** + * Built-in command: gg + * Quick access to Git commands + */ +int lsh_gg(char **args) { + if (args[1] == NULL) { + printf("Usage: gg \n"); + printf("Available commands:\n"); + printf(" s - status\n"); + printf(" c - commit\n"); + printf(" p - pull\n"); + printf(" ps - push\n"); + printf(" a - add .\n"); + printf(" l - log\n"); + printf(" d - diff\n"); + printf(" b - branch\n"); + printf(" ch - checkout\n"); + return 1; + } + + // Execute the appropriate git command based on shorthand + if (strcmp(args[1], "s") == 0) { + system("git status"); + } else if (strcmp(args[1], "c") == 0) { + if (args[2] != NULL) { + char command[1024]; + sprintf(command, "git commit -m \"%s\"", args[2]); + system(command); + } else { + system("git commit"); + } + } else if (strcmp(args[1], "p") == 0) { + system("git pull"); + } else if (strcmp(args[1], "ps") == 0) { + system("git push"); + } else if (strcmp(args[1], "a") == 0) { + system("git add ."); + } else if (strcmp(args[1], "l") == 0) { + system("git log --oneline -10"); + } else if (strcmp(args[1], "d") == 0) { + system("git diff"); + } else if (strcmp(args[1], "b") == 0) { + system("git branch"); + } else if (strcmp(args[1], "ch") == 0) { + if (args[2] != NULL) { + char command[1024]; + sprintf(command, "git checkout %s", args[2]); + system(command); + } else { + printf("Please specify a branch to checkout\n"); + } + } else { + printf("Unknown git command shorthand: %s\n", args[1]); + } + + return 1; +} \ No newline at end of file diff --git a/builtins.h b/builtins.h new file mode 100644 index 0000000..04101ad --- /dev/null +++ b/builtins.h @@ -0,0 +1,100 @@ +/** + * builtins.h + * Declarations for all built-in shell commands + */ + +#ifndef BUILTINS_H +#define BUILTINS_H + +#include "common.h" +#include + +// Syntax highlighting definitions using ANSI colors +#define COLOR_DEFAULT ANSI_COLOR_RESET +#define COLOR_KEYWORD ANSI_COLOR_CYAN +#define COLOR_STRING ANSI_COLOR_GREEN +#define COLOR_COMMENT "\x1b[90m" // Dark gray +#define COLOR_NUMBER ANSI_COLOR_MAGENTA +#define COLOR_PREPROCESSOR ANSI_COLOR_YELLOW +#define COLOR_IDENTIFIER "\x1b[97m" // Bright white + +// Add declarations for color functions +void set_color(int color); +void reset_color(); + +// History command implementation +#define HISTORY_SIZE 10 + +// New struct to hold history entries with timestamps +typedef struct { + char *command; + time_t timestamp; +} HistoryEntry; + +// History variables - made extern to be accessible from line_reader.c +extern HistoryEntry command_history[HISTORY_SIZE]; +extern int history_count; +extern int history_index; + +// Built-in command declarations +int lsh_cd(char **args); +int lsh_help(char **args); +int lsh_exit(char **args); +int lsh_dir(char **args); +int lsh_clear(char **args); +int lsh_mkdir(char **args); +int lsh_rmdir(char **args); +int lsh_del(char **args); +int lsh_touch(char **args); +int lsh_pwd(char **args); +int lsh_cat(char **args); +int lsh_history(char **args); +int lsh_copy(char **args); +int lsh_paste(char **args); +int lsh_move(char **args); +int lsh_ps(char **args); +int lsh_news(char **args); +// Alias command declarations - added for alias support +int lsh_alias(char **args); +int lsh_unalias(char **args); +int lsh_aliases(char **args); // New command to list all aliases +// Bookmark command declarations - added for bookmark support +int lsh_bookmark(char **args); +int lsh_bookmarks(char **args); +int lsh_goto(char **args); +int lsh_unbookmark(char **args); +int lsh_focus_timer(char **args); +int lsh_weather(char **args); +// Text search command +int lsh_grep(char **args); +int lsh_actual_grep(char **args); +int lsh_ripgrep(char **args); +int lsh_fzf_native(char **args); +int lsh_clip(char **args); +int lsh_echo(char **args); +int lsh_self_destruct(); +int lsh_theme(char **args); +int lsh_loc(char **args); +int lsh_git_status(char **args); +int lsh_gg(char **args); + +// Add command to history +void lsh_add_to_history(const char *command); + +// Get number of builtin commands +int lsh_num_builtins(void); + +// Expose the builtin command strings and function pointers +extern char *builtin_str[]; +extern int (*builtin_func[])(char **); + +/** + * Extract a string value from a JSON object + * + * @param json The JSON string to parse + * @param key The key to find + * @return Allocated string containing the value (caller must free) + */ +char *extract_json_string(const char *json, const char *key); + +#endif // BUILTINS_H \ No newline at end of file diff --git a/builtins.o b/builtins.o new file mode 100644 index 0000000000000000000000000000000000000000..c8b5afb6d4ba97ecf181ed69526d9187042ace8a GIT binary patch literal 44280 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 literal 0 HcmV?d00001 diff --git a/common.h b/common.h new file mode 100644 index 0000000..f490181 --- /dev/null +++ b/common.h @@ -0,0 +1,115 @@ +/** + * common.h + * Common includes, defines and macros used throughout the shell + */ + +#ifndef COMMON_H +#define COMMON_H + +// Standard library includes +#include +#include +#include +#include // For isprint +#include // For file control +#include // For POSIX API (replaces direct.h) +#include +#include // For waitpid +#include // For stat (replaces fileapi.h) +#include // For terminal control +#include // For console dimensions +#include // For signal handling +#include // For time functions +#include // For PATH_MAX + +// Define PATH_MAX if not defined +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + +// Common defines +#define LSH_RL_BUFSIZE 1024 +#define LSH_TOK_BUFSIZE 64 +#define LSH_TOK_DELIM " \t\r\n\a" + +// Terminal control and color codes (ANSI sequences) +#define ANSI_COLOR_RESET "\x1b[0m" +#define ANSI_COLOR_BLACK "\x1b[30m" +#define ANSI_COLOR_RED "\x1b[31m" +#define ANSI_COLOR_GREEN "\x1b[32m" +#define ANSI_COLOR_YELLOW "\x1b[33m" +#define ANSI_COLOR_BLUE "\x1b[34m" +#define ANSI_COLOR_MAGENTA "\x1b[35m" +#define ANSI_COLOR_CYAN "\x1b[36m" +#define ANSI_COLOR_WHITE "\x1b[37m" + +// Background colors +#define ANSI_BG_BLACK "\x1b[40m" +#define ANSI_BG_RED "\x1b[41m" +#define ANSI_BG_GREEN "\x1b[42m" +#define ANSI_BG_YELLOW "\x1b[43m" +#define ANSI_BG_BLUE "\x1b[44m" +#define ANSI_BG_MAGENTA "\x1b[45m" +#define ANSI_BG_CYAN "\x1b[46m" +#define ANSI_BG_WHITE "\x1b[47m" + +// Cursor movement and screen control +#define ANSI_CLEAR_SCREEN "\x1b[2J" +#define ANSI_CURSOR_HOME "\x1b[H" +#define ANSI_SAVE_CURSOR "\x1b[s" +#define ANSI_RESTORE_CURSOR "\x1b[u" + +// Key code definitions used by the line reader +#define KEY_BACKSPACE 127 // Different on Linux +#define KEY_TAB 9 +#define KEY_ENTER 10 // Linux: 10 (LF) or 13 (CR) +#define KEY_ESCAPE 27 + +// Special keys (Linux terminal uses escape sequences) +// These will need handling in the line reader +#define KEY_UP 1000 +#define KEY_DOWN 1001 +#define KEY_LEFT 1002 +#define KEY_RIGHT 1003 +#define KEY_SHIFT_ENTER 1010 + +// Typedefs for compatibility +typedef unsigned int UINT; +typedef unsigned short WORD; +typedef int BOOL; +typedef int HANDLE; +typedef int DWORD; + +// Define Windows constants +#define FALSE 0 +#define TRUE 1 + +// Struct to replace COORD +typedef struct { + short X; + short Y; +} COORD; + +// Struct to replace SMALL_RECT +typedef struct { + short Left; + short Top; + short Right; + short Bottom; +} SMALL_RECT; + +// Struct to replace CONSOLE_SCREEN_BUFFER_INFO +typedef struct { + COORD dwSize; + COORD dwCursorPosition; + WORD wAttributes; + SMALL_RECT srWindow; +} CONSOLE_SCREEN_BUFFER_INFO; + +// Struct to replace CONSOLE_CURSOR_INFO +typedef struct { + DWORD dwSize; + BOOL bVisible; +} CONSOLE_CURSOR_INFO; + +#endif // COMMON_H diff --git a/countdown_timer.c b/countdown_timer.c new file mode 100644 index 0000000..d238f2a --- /dev/null +++ b/countdown_timer.c @@ -0,0 +1,306 @@ +/** + * countdown_timer.c + * Implementation of a focus timer that integrates with the shell status bar + */ + +#include "countdown_timer.h" +#include "common.h" +#include "shell.h" +#include "themes.h" +#include +#include +#include +#include +#include +#include +#include +#include + +// Global timer state +static struct { + BOOL is_active; // Whether timer is currently running + time_t end_time; // When timer will expire (in seconds since epoch) + char display_text[64]; // Current timer display text + char session_name[128]; // Optional session name + pthread_t timer_thread; // Timer thread ID + BOOL should_exit; // Flag to signal thread exit + BOOL is_temporarily_hidden; // Flag to hide timer while running external programs +} timer_state = {FALSE, 0, "", "", 0, FALSE, FALSE}; + +/** + * Update timer display text based on remaining time + */ +static void update_timer_display(void) { + if (!timer_state.is_active) { + strcpy(timer_state.display_text, ""); + return; + } + + // Calculate remaining time + time_t now = time(NULL); + int seconds_left = (int)difftime(timer_state.end_time, now); + + if (seconds_left <= 0) { + // Timer has expired + if (strlen(timer_state.session_name) > 0) { + snprintf(timer_state.display_text, sizeof(timer_state.display_text), + "Session '%s' complete!", timer_state.session_name); + } else { + strcpy(timer_state.display_text, "Timer complete!"); + } + return; + } + + // Format time as MM:SS + int minutes = seconds_left / 60; + int seconds = seconds_left % 60; + + if (strlen(timer_state.session_name) > 0) { + snprintf(timer_state.display_text, sizeof(timer_state.display_text), + "%s: %02d:%02d remaining", timer_state.session_name, minutes, seconds); + } else { + snprintf(timer_state.display_text, sizeof(timer_state.display_text), + "Focus: %02d:%02d remaining", minutes, seconds); + } +} + +/** + * Timer thread function + */ +static void *timer_thread_func(void *param) { + while (!timer_state.should_exit) { + // Update timer display + update_timer_display(); + + // Check if timer has expired + time_t now = time(NULL); + if (difftime(timer_state.end_time, now) <= 0) { + // Play a bell sound + printf("\a"); + fflush(stdout); + + // Update status bar with completion message + update_timer_display(); + + // Keep thread running to display completion message + } + + // Sleep for 1 second + sleep(1); + } + + return NULL; +} + +/** + * Start a new countdown timer + */ +int start_countdown_timer(int seconds, const char *name) { + // Stop any existing timer + if (timer_state.is_active) { + stop_countdown_timer(); + } + + // Set timer parameters + timer_state.end_time = time(NULL) + seconds; + timer_state.is_active = TRUE; + timer_state.should_exit = FALSE; + timer_state.is_temporarily_hidden = FALSE; + + // Set optional session name + if (name && *name) { + strncpy(timer_state.session_name, name, sizeof(timer_state.session_name) - 1); + timer_state.session_name[sizeof(timer_state.session_name) - 1] = '\0'; + } else { + timer_state.session_name[0] = '\0'; + } + + // Initialize display text + update_timer_display(); + + // Create timer thread + int ret = pthread_create(&timer_state.timer_thread, NULL, timer_thread_func, NULL); + if (ret != 0) { + fprintf(stderr, "Failed to create timer thread: %s\n", strerror(ret)); + timer_state.is_active = FALSE; + return 0; + } + + // Detach thread so it cleans up automatically + pthread_detach(timer_state.timer_thread); + + return 1; +} + +/** + * Stop the current countdown timer + */ +void stop_countdown_timer() { + if (!timer_state.is_active) { + return; + } + + // Signal thread to exit + timer_state.should_exit = TRUE; + + // Wait for thread to terminate (with timeout) + // Use a more portable approach since pthread_timedjoin_np is GNU-specific + + // Set a timeout of 2 seconds + struct timespec timeout; + timeout.tv_sec = 2; + timeout.tv_nsec = 0; + + // Sleep for the timeout period - the thread will keep running + // and clean itself up since we detached it + nanosleep(&timeout, NULL); + + // Reset timer state + timer_state.is_active = FALSE; + timer_state.display_text[0] = '\0'; + timer_state.session_name[0] = '\0'; +} + +/** + * Check if a timer is currently active + */ +BOOL is_timer_active() { + return timer_state.is_active; +} + +/** + * Get the current timer display text + */ +const char *get_timer_display() { + if (timer_state.is_temporarily_hidden || !timer_state.is_active) { + return ""; + } + return timer_state.display_text; +} + +/** + * Temporarily hide the timer display + */ +void hide_timer_display(void) { + timer_state.is_temporarily_hidden = TRUE; +} + +/** + * Restore the timer display after it was hidden + */ +void show_timer_display(void) { + timer_state.is_temporarily_hidden = FALSE; +} + +/** + * Parse time string in format "XhYmZs" to seconds + */ +static int parse_time_string(const char *time_str) { + if (!time_str || !*time_str) { + return 0; + } + + int total_seconds = 0; + char *str = strdup(time_str); + if (!str) { + return 0; + } + + char *pos = str; + char *next_pos; + int value; + + while (*pos) { + // Skip non-digits + while (*pos && !isdigit(*pos)) { + pos++; + } + + if (!*pos) { + break; + } + + // Parse number + value = (int)strtol(pos, &next_pos, 10); + if (pos == next_pos) { + break; + } + + // Skip whitespace + pos = next_pos; + while (*pos && isspace(*pos)) { + pos++; + } + + // Check unit + if (*pos == 'h' || *pos == 'H') { + total_seconds += value * 3600; + } else if (*pos == 'm' || *pos == 'M') { + total_seconds += value * 60; + } else if (*pos == 's' || *pos == 'S') { + total_seconds += value; + } else { + // No unit specified, assume minutes + total_seconds += value * 60; + } + + // Move to next part + if (*pos) { + pos++; + } + } + + free(str); + return total_seconds; +} + +/** + * Command handler for the focus timer command + */ +int lsh_focus_timer(char **args) { + if (!args[1]) { + // No arguments - show help + printf("Usage: focus_timer [start|stop] [duration] [session name]\n"); + printf("Examples:\n"); + printf(" focus_timer start 25m \"Coding session\" # Start a 25-minute timer\n"); + printf(" focus_timer start 1h30m # Start a 1 hour 30 minute timer\n"); + printf(" focus_timer stop # Stop the current timer\n"); + printf("Current status: %s\n", + timer_state.is_active ? timer_state.display_text : "No active timer"); + return 1; + } + + if (strcmp(args[1], "stop") == 0) { + if (timer_state.is_active) { + printf("Stopping timer...\n"); + stop_countdown_timer(); + } else { + printf("No active timer to stop.\n"); + } + return 1; + } + + if (strcmp(args[1], "start") == 0) { + if (!args[2]) { + printf("Error: Duration required. Example: focus_timer start 25m\n"); + return 1; + } + + int seconds = parse_time_string(args[2]); + if (seconds <= 0) { + printf("Error: Invalid duration format. Examples: 25m, 1h30m, 90s\n"); + return 1; + } + + const char *session_name = args[3] ? args[3] : ""; + if (start_countdown_timer(seconds, session_name)) { + printf("Timer started: %s\n", timer_state.display_text); + } else { + printf("Failed to start timer.\n"); + } + return 1; + } + + printf("Unknown timer command: %s\n", args[1]); + return 1; +} \ No newline at end of file diff --git a/countdown_timer.h b/countdown_timer.h new file mode 100644 index 0000000..6db1d2d --- /dev/null +++ b/countdown_timer.h @@ -0,0 +1,57 @@ +/** + * countdown_timer.h + * Header for focus timer functionality + */ + +#ifndef COUNTDOWN_TIMER_H +#define COUNTDOWN_TIMER_H + +#include "common.h" + +/** + * Start a new countdown timer + * + * @param seconds Total duration in seconds + * @param name Optional name for the timer session + * @return 1 if successful, 0 on failure + */ +int start_countdown_timer(int seconds, const char *name); + +/** + * Stop the current countdown timer + */ +void stop_countdown_timer(); + +/** + * Check if a timer is currently active + * + * @return TRUE if timer is active, FALSE otherwise + */ +BOOL is_timer_active(); + +/** + * Get the current timer display text + * + * @return Pointer to the display text string + */ +const char *get_timer_display(); + +/** + * Temporarily hide the timer display (used when running external programs) + */ +void hide_timer_display(void); + +/** + * Restore the timer display after it was hidden + */ +void show_timer_display(void); + +/** + * Command handler for the "timer" command + * + * @param args Command arguments + * @return 1 to continue shell, 0 to exit + */ +int lsh_focus_timer(char **args); + +#endif // COUNTDOWN_TIMER_H diff --git a/countdown_timer.o b/countdown_timer.o new file mode 100644 index 0000000000000000000000000000000000000000..eeb0f8abe7c6e58502c8f790cb9c2d1dde87cb36 GIT binary patch literal 16080 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 0 && line[len - 1] == '\n') { + line[len - 1] = '\0'; + len--; + } + + // Skip empty lines and comments + if (len == 0 || line[0] == '#') + continue; + + // Add the city + add_favorite_city(line); + } + + fclose(file); + return 1; +} + +/** + * Save favorite cities to file + */ +int save_favorite_cities(void) { + FILE *file = fopen(favorite_cities_file_path, "w"); + if (!file) { + fprintf(stderr, "lsh: error: could not save favorite cities to %s\n", + favorite_cities_file_path); + return 0; + } + + // Write header comment + fprintf(file, "# LSH favorite cities file\n"); + fprintf(file, + "# Each line represents a favorite city for weather lookups\n\n"); + + // Write each city + for (int i = 0; i < favorite_city_count; i++) { + fprintf(file, "%s\n", favorite_cities[i].name); + } + + fclose(file); + return 1; +} + +/** + * Add a new favorite city + */ +int add_favorite_city(const char *name) { + if (!name) + return 0; + + // Check if we need to resize the array + if (favorite_city_count >= favorite_city_capacity) { + favorite_city_capacity *= 2; + CityEntry *new_cities = (CityEntry *)realloc( + favorite_cities, favorite_city_capacity * sizeof(CityEntry)); + if (!new_cities) { + fprintf(stderr, "lsh: allocation error in add_favorite_city\n"); + return 0; + } + favorite_cities = new_cities; + } + + // Check if the city already exists + for (int i = 0; i < favorite_city_count; i++) { + if (strcasecmp(favorite_cities[i].name, name) == 0) { + // City already exists + return 1; + } + } + + // Add new city + strncpy(favorite_cities[favorite_city_count].name, name, + sizeof(favorite_cities[favorite_city_count].name) - 1); + favorite_cities[favorite_city_count] + .name[sizeof(favorite_cities[favorite_city_count].name) - 1] = '\0'; + favorite_city_count++; + + return 1; +} + +/** + * Remove a favorite city + */ +int remove_favorite_city(const char *name) { + if (!name) + return 0; + + for (int i = 0; i < favorite_city_count; i++) { + if (strcasecmp(favorite_cities[i].name, name) == 0) { + // Shift remaining cities + for (int j = i; j < favorite_city_count - 1; j++) { + strcpy(favorite_cities[j].name, favorite_cities[j + 1].name); + } + + favorite_city_count--; + return 1; + } + } + + return 0; // City not found +} + +/** + * Find a favorite city by name + */ +CityEntry *find_favorite_city(const char *name) { + if (!name) + return NULL; + + for (int i = 0; i < favorite_city_count; i++) { + if (strcasecmp(favorite_cities[i].name, name) == 0) { + return &favorite_cities[i]; + } + } + + return NULL; +} + +/** + * Get favorite city names for tab completion + */ +char **get_favorite_city_names(int *count) { + if (favorite_city_count == 0) { + *count = 0; + return NULL; + } + + char **names = (char **)malloc(favorite_city_count * sizeof(char *)); + if (!names) { + *count = 0; + return NULL; + } + + for (int i = 0; i < favorite_city_count; i++) { + names[i] = strdup(favorite_cities[i].name); + } + + *count = favorite_city_count; + return names; +} + +/** + * Command handler for the "cities" command + * Usage: + * cities add + * cities remove + * cities list + */ +int lsh_cities(char **args) { + if (args[1] == NULL) { + // No subcommand - show usage + printf("Usage: cities [arguments]\n"); + printf("Commands:\n"); + printf(" add Add a city to favorites\n"); + printf(" remove Remove a city from favorites\n"); + printf(" list List all favorite cities\n"); + return 1; + } + + // Handle subcommands + if (strcmp(args[1], "add") == 0) { + if (args[2] == NULL) { + printf("Usage: cities add \n"); + return 1; + } + + // Combine all arguments after "add" into a single city name + char city_name[256] = ""; + strncpy(city_name, args[2], sizeof(city_name) - 1); + + for (int i = 3; args[i] != NULL; i++) { + strncat(city_name, " ", sizeof(city_name) - strlen(city_name) - 1); + strncat(city_name, args[i], sizeof(city_name) - strlen(city_name) - 1); + } + + if (add_favorite_city(city_name)) { + save_favorite_cities(); + printf("Added '%s' to favorite cities\n", city_name); + } + + } else if (strcmp(args[1], "remove") == 0) { + if (args[2] == NULL) { + printf("Usage: cities remove \n"); + return 1; + } + + // Combine all arguments after "remove" into a single city name + char city_name[256] = ""; + strncpy(city_name, args[2], sizeof(city_name) - 1); + + for (int i = 3; args[i] != NULL; i++) { + strncat(city_name, " ", sizeof(city_name) - strlen(city_name) - 1); + strncat(city_name, args[i], sizeof(city_name) - strlen(city_name) - 1); + } + + if (remove_favorite_city(city_name)) { + save_favorite_cities(); + printf("Removed '%s' from favorite cities\n", city_name); + } else { + printf("City '%s' not found in favorites\n", city_name); + } + + } else if (strcmp(args[1], "list") == 0) { + // List all favorite cities + if (favorite_city_count == 0) { + printf("No favorite cities defined\n"); + return 1; + } + + printf("\nFavorite Cities:\n\n"); + + // Display cities in a nice format + for (int i = 0; i < favorite_city_count; i++) { + // Print city name with color + printf(ANSI_COLOR_CYAN " %s" ANSI_COLOR_RESET "\n", favorite_cities[i].name); + } + printf("\n"); + + } else { + printf("Unknown command: %s\n", args[1]); + printf("Available commands: add, remove, list\n"); + } + + return 1; +} diff --git a/favorite_cities.h b/favorite_cities.h new file mode 100644 index 0000000..1ff21d2 --- /dev/null +++ b/favorite_cities.h @@ -0,0 +1,50 @@ +/** + * favorite_cities.h + * Functions for managing favorite cities for weather lookups + */ + +#ifndef FAVORITE_CITIES_H +#define FAVORITE_CITIES_H + +#include "common.h" + +// Structure to represent a favorite city +typedef struct { + char name[128]; // City name +} CityEntry; + +// Initialize favorite cities system +void init_favorite_cities(void); + +// Clean up favorite cities system +void cleanup_favorite_cities(void); + +// Shutdown favorite cities system (save and cleanup) +void shutdown_favorite_cities(void); + +// Load favorite cities from file +int load_favorite_cities(void); + +// Save favorite cities to file +int save_favorite_cities(void); + +// Add a new favorite city +int add_favorite_city(const char *name); + +// Remove a favorite city +int remove_favorite_city(const char *name); + +// Find a favorite city by name +CityEntry *find_favorite_city(const char *name); + +// Get favorite city names for tab completion +char **get_favorite_city_names(int *count); + +// Command handlers +int lsh_cities(char **args); // Main cities command handler + +// Global favorite cities array +extern CityEntry *favorite_cities; +extern int favorite_city_count; + +#endif // FAVORITE_CITIES_H diff --git a/favorite_cities.o b/favorite_cities.o new file mode 100644 index 0000000000000000000000000000000000000000..e1e60d6efb3b32608c585b229417eabcc37df119 GIT binary patch literal 18480 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 +#include // For strcasecmp and strncasecmp + +/** + * Filter a table based on a condition (e.g., where size > 10kb) + */ +TableData* lsh_where(TableData *input, char **args) { + if (!input || !args || !args[0]) { + fprintf(stderr, "lsh: where: missing arguments\n"); + fprintf(stderr, "Usage: ... | where FIELD OPERATOR VALUE\n"); + fprintf(stderr, " e.g.: ls | where size > 10kb\n"); + return NULL; + } + + // Parse filter condition (field, operator, value) + char *field = args[0]; + char *op = NULL; + char *value = NULL; + + // Find operator and value + if (args[1] != NULL) { + if (strcmp(args[1], ">") == 0 || + strcmp(args[1], "<") == 0 || + strcmp(args[1], "==") == 0 || + strcmp(args[1], ">=") == 0 || + strcmp(args[1], "<=") == 0) { + op = args[1]; + value = args[2]; + } + } + + if (!op || !value) { + fprintf(stderr, "lsh: where: invalid filter condition\n"); + fprintf(stderr, "Usage: ... | where FIELD OPERATOR VALUE\n"); + fprintf(stderr, " e.g.: ls | where size > 10kb\n"); + return NULL; + } + + // Find field index + int field_idx = -1; + for (int i = 0; i < input->header_count; i++) { + if (strcasecmp(input->headers[i], field) == 0) { + field_idx = i; + break; + } + } + + if (field_idx == -1) { + fprintf(stderr, "lsh: where: unknown field '%s'\n", field); + fprintf(stderr, "Available fields: "); + for (int i = 0; i < input->header_count; i++) { + fprintf(stderr, "%s%s", i > 0 ? ", " : "", input->headers[i]); + } + fprintf(stderr, "\n"); + return NULL; + } + + // Create new filtered table + return filter_table(input, field, op, value); +} + +/** + * Sort a table based on a column (e.g., sort-by size desc) + */ +TableData* lsh_sort_by(TableData *input, char **args) { + if (!input || !args || !args[0]) { + fprintf(stderr, "lsh: sort-by: missing arguments\n"); + fprintf(stderr, "Usage: ... | sort-by FIELD [asc|desc]\n"); + fprintf(stderr, " e.g.: ls | sort-by size desc\n"); + return NULL; + } + + // Parse sort field and direction + char *field = args[0]; + int descending = 0; + + // Check if direction is specified + if (args[1] != NULL) { + if (strcasecmp(args[1], "desc") == 0 || + strcasecmp(args[1], "descending") == 0) { + descending = 1; + } + } + + // Find field index + int field_idx = -1; + for (int i = 0; i < input->header_count; i++) { + if (strcasecmp(input->headers[i], field) == 0) { + field_idx = i; + break; + } + } + + if (field_idx == -1) { + fprintf(stderr, "lsh: sort-by: unknown field '%s'\n", field); + fprintf(stderr, "Available fields: "); + for (int i = 0; i < input->header_count; i++) { + fprintf(stderr, "%s%s", i > 0 ? ", " : "", input->headers[i]); + } + fprintf(stderr, "\n"); + return NULL; + } + + // Create a copy of the table + TableData *result = create_table(input->headers, input->header_count); + if (!result) { + return NULL; + } + + // Copy all rows to the new table + for (int i = 0; i < input->row_count; i++) { + DataValue *row_copy = (DataValue*)malloc(input->header_count * sizeof(DataValue)); + if (!row_copy) { + fprintf(stderr, "lsh: allocation error in sort_by\n"); + free_table(result); + return NULL; + } + + for (int j = 0; j < input->header_count; j++) { + row_copy[j] = copy_data_value(&input->rows[i][j]); + } + + add_table_row(result, row_copy); + } + + // Now sort the rows based on the specified column + // Bubble sort for simplicity (not efficient for large datasets) + for (int i = 0; i < result->row_count - 1; i++) { + for (int j = 0; j < result->row_count - i - 1; j++) { + int compare_result = 0; + + // Compare based on data type + if (result->rows[j][field_idx].type == TYPE_STRING || + result->rows[j][field_idx].type == TYPE_SIZE) { + // Handle special case for sizes (KB, MB, etc.) + if (strcasecmp(result->headers[field_idx], "Size") == 0 || + strcasecmp(result->headers[field_idx], "Memory") == 0) { + long size1 = extract_size_bytes(result->rows[j][field_idx].value.str_val); + long size2 = extract_size_bytes(result->rows[j+1][field_idx].value.str_val); + compare_result = (size1 > size2) ? 1 : (size1 < size2) ? -1 : 0; + } else { + // Regular string comparison + compare_result = strcasecmp( + result->rows[j][field_idx].value.str_val, + result->rows[j+1][field_idx].value.str_val + ); + } + } else if (result->rows[j][field_idx].type == TYPE_INT) { + int val1 = result->rows[j][field_idx].value.int_val; + int val2 = result->rows[j+1][field_idx].value.int_val; + compare_result = (val1 > val2) ? 1 : (val1 < val2) ? -1 : 0; + } else if (result->rows[j][field_idx].type == TYPE_FLOAT) { + float val1 = result->rows[j][field_idx].value.float_val; + float val2 = result->rows[j+1][field_idx].value.float_val; + compare_result = (val1 > val2) ? 1 : (val1 < val2) ? -1 : 0; + } + + // If descending, invert comparison result + if (descending) { + compare_result = -compare_result; + } + + // Swap if needed + if (compare_result > 0) { + DataValue *temp = result->rows[j]; + result->rows[j] = result->rows[j+1]; + result->rows[j+1] = temp; + } + } + } + + return result; +} + +/** + * Select specific columns from a table + * Supports both space-separated and comma-separated field names + */ +TableData* lsh_select(TableData *input, char **args) { + if (!input || !args || !args[0]) { + fprintf(stderr, "lsh: select: missing arguments\n"); + fprintf(stderr, "Usage: ... | select FIELD1 FIELD2 ...\n"); + fprintf(stderr, " e.g.: ls | select Name Size\n"); + return NULL; + } + + // Count how many fields we have + int num_fields = 0; + int arg_index = 0; + + // First pass: count fields + while (args[arg_index] != NULL) { + // Check if this argument contains commas + char *p = args[arg_index]; + int commas_in_arg = 0; + + while (*p) { + if (*p == ',') { + commas_in_arg++; + } + p++; + } + + if (commas_in_arg > 0) { + // Add number of comma-separated fields (commas + 1) + num_fields += commas_in_arg + 1; + } else { + // Just one field in this argument + num_fields++; + } + + arg_index++; + } + + // Allocate array for field indices + int *field_indices = (int*)malloc(num_fields * sizeof(int)); + if (!field_indices) { + fprintf(stderr, "lsh: allocation error in select\n"); + return NULL; + } + + // Second pass: process field names + int field_count = 0; + arg_index = 0; + + while (args[arg_index] != NULL && field_count < num_fields) { + // Make a copy since we'll modify it with strtok + char *arg_copy = strdup(args[arg_index]); + if (!arg_copy) { + fprintf(stderr, "lsh: allocation error in select\n"); + free(field_indices); + return NULL; + } + + // Check if this argument contains commas + if (strchr(arg_copy, ',')) { + // Handle comma-separated fields + char *field_token; + char *saveptr; + + field_token = strtok_r(arg_copy, ",", &saveptr); + while (field_token && field_count < num_fields) { + // Trim whitespace + while (isspace(*field_token)) field_token++; + char *end = field_token + strlen(field_token) - 1; + while (end > field_token && isspace(*end)) end--; + *(end + 1) = '\0'; + + // Find field index + int found = 0; + for (int i = 0; i < input->header_count; i++) { + if (strcasecmp(input->headers[i], field_token) == 0) { + field_indices[field_count++] = i; + found = 1; + break; + } + } + + if (!found) { + fprintf(stderr, "lsh: select: unknown field '%s'\n", field_token); + free(field_indices); + free(arg_copy); + return NULL; + } + + field_token = strtok_r(NULL, ",", &saveptr); + } + } else { + // This is a single field name (no commas) + char *field = arg_copy; + + // Trim whitespace + while (isspace(*field)) field++; + char *end = field + strlen(field) - 1; + while (end > field && isspace(*end)) end--; + *(end + 1) = '\0'; + + // Find field index + int found = 0; + for (int i = 0; i < input->header_count; i++) { + if (strcasecmp(input->headers[i], field) == 0) { + field_indices[field_count++] = i; + found = 1; + break; + } + } + + if (!found) { + fprintf(stderr, "lsh: select: unknown field '%s'\n", field); + free(arg_copy); + free(field_indices); + return NULL; + } + } + + free(arg_copy); + arg_index++; + } + + // Create new headers for result table + char **new_headers = (char**)malloc(field_count * sizeof(char*)); + if (!new_headers) { + fprintf(stderr, "lsh: allocation error in select\n"); + free(field_indices); + return NULL; + } + + for (int i = 0; i < field_count; i++) { + new_headers[i] = strdup(input->headers[field_indices[i]]); + } + + // Create result table with new headers + TableData *result = create_table(new_headers, field_count); + + // Free temporary header array + for (int i = 0; i < field_count; i++) { + free(new_headers[i]); + } + free(new_headers); + + if (!result) { + free(field_indices); + return NULL; + } + + // Copy rows with only the selected columns + for (int i = 0; i < input->row_count; i++) { + DataValue *row = (DataValue*)malloc(field_count * sizeof(DataValue)); + if (!row) { + fprintf(stderr, "lsh: allocation error in select\n"); + free_table(result); + free(field_indices); + return NULL; + } + + for (int j = 0; j < field_count; j++) { + row[j] = copy_data_value(&input->rows[i][field_indices[j]]); + } + + add_table_row(result, row); + } + + free(field_indices); + return result; +} + +/** + * Case-insensitive substring search (strcasestr equivalent for Windows) + */ +char *my_strcasestr(const char *haystack, const char *needle) { + if (!haystack || !needle) return NULL; + + size_t needle_len = strlen(needle); + if (needle_len == 0) return (char*)haystack; + + size_t haystack_len = strlen(haystack); + if (haystack_len < needle_len) return NULL; + + for (size_t i = 0; i <= haystack_len - needle_len; i++) { + if (strncasecmp(haystack + i, needle, needle_len) == 0) { + return (char*)(haystack + i); + } + } + + return NULL; +} + +/** + * Filter rows where a column contains a substring + */ +TableData* lsh_contains(TableData *input, char **args) { + if (!input || !args || !args[0] || !args[1]) { + fprintf(stderr, "lsh: contains: missing arguments\n"); + fprintf(stderr, "Usage: ... | contains FIELD VALUE\n"); + fprintf(stderr, " e.g.: ls | contains Name .exe\n"); + return NULL; + } + + // Parse arguments + char *field = args[0]; + char *value = args[1]; + + // Find field index + int field_idx = -1; + for (int i = 0; i < input->header_count; i++) { + if (strcasecmp(input->headers[i], field) == 0) { + field_idx = i; + break; + } + } + + if (field_idx == -1) { + fprintf(stderr, "lsh: contains: unknown field '%s'\n", field); + fprintf(stderr, "Available fields: "); + for (int i = 0; i < input->header_count; i++) { + fprintf(stderr, "%s%s", i > 0 ? ", " : "", input->headers[i]); + } + fprintf(stderr, "\n"); + return NULL; + } + + // Create result table with same headers + TableData *result = create_table(input->headers, input->header_count); + if (!result) { + return NULL; + } + + // Filter rows based on whether the specified column contains the substring + for (int i = 0; i < input->row_count; i++) { + int include_row = 0; + + // Only string fields can be checked with contains + if (input->rows[i][field_idx].type == TYPE_STRING || + input->rows[i][field_idx].type == TYPE_SIZE) { + char *cell_value = input->rows[i][field_idx].value.str_val; + + // Case-insensitive substring check + char *found = my_strcasestr(cell_value, value); + include_row = (found != NULL); + } + + if (include_row) { + // Create a copy of the row for the result table + DataValue *row_copy = (DataValue*)malloc(input->header_count * sizeof(DataValue)); + if (!row_copy) { + fprintf(stderr, "lsh: allocation error in contains\n"); + free_table(result); + return NULL; + } + + for (int j = 0; j < input->header_count; j++) { + row_copy[j] = copy_data_value(&input->rows[i][j]); + } + + add_table_row(result, row_copy); + } + } + + return result; +} + +/** + * Limit the number of rows displayed + */ +TableData* lsh_limit(TableData *input, char **args) { + if (!input || !args || !args[0]) { + fprintf(stderr, "lsh: limit: missing arguments\n"); + fprintf(stderr, "Usage: ... | limit N\n"); + fprintf(stderr, " e.g.: ls | sort-by Size desc | limit 5\n"); + return NULL; + } + + // Parse limit + int limit = atoi(args[0]); + if (limit <= 0) { + fprintf(stderr, "lsh: limit: invalid limit '%s', must be a positive number\n", args[0]); + return NULL; + } + + // Create result table with same headers + TableData *result = create_table(input->headers, input->header_count); + if (!result) { + return NULL; + } + + // Copy only the specified number of rows + int rows_to_copy = (limit < input->row_count) ? limit : input->row_count; + + for (int i = 0; i < rows_to_copy; i++) { + DataValue *row_copy = (DataValue*)malloc(input->header_count * sizeof(DataValue)); + if (!row_copy) { + fprintf(stderr, "lsh: allocation error in limit\n"); + free_table(result); + return NULL; + } + + for (int j = 0; j < input->header_count; j++) { + row_copy[j] = copy_data_value(&input->rows[i][j]); + } + + add_table_row(result, row_copy); + } + + return result; +} + +// Define the filter arrays here +char *filter_str[] = { + "where", + "sort-by", + "select", + "contains", + "limit" +}; + +TableData* (*filter_func[]) (TableData*, char**) = { + &lsh_where, + &lsh_sort_by, + &lsh_select, + &lsh_contains, + &lsh_limit +}; + +int filter_count = sizeof(filter_str) / sizeof(char*); diff --git a/filters.h b/filters.h new file mode 100644 index 0000000..512d2ca --- /dev/null +++ b/filters.h @@ -0,0 +1,66 @@ +/** + * filters.h + * Declarations for filter commands (where, sort-by, etc.) + */ + +#ifndef FILTERS_H +#define FILTERS_H + +#include "structured_data.h" + +/** + * Filter a table based on a condition (e.g., where size > 10kb) + * + * @param input The input table + * @param args Command arguments + * @return Filtered table or NULL on error + */ +TableData* lsh_where(TableData *input, char **args); + +/** + * Sort a table based on a column (e.g., sort-by size desc) + * + * @param input The input table + * @param args Command arguments + * @return Sorted table or NULL on error + */ +TableData* lsh_sort_by(TableData *input, char **args); + +/** + * Select specific columns from a table + * + * @param input The input table + * @param args Command arguments + * @return Table with selected columns or NULL on error + */ +TableData* lsh_select(TableData *input, char **args); + +/** + * Filter rows where a column contains a substring + * + * @param input The input table + * @param args Command arguments + * @return Filtered table or NULL on error + */ +TableData* lsh_contains(TableData *input, char **args); + +/** + * Limit the number of rows displayed + * + * @param input The input table + * @param args Command arguments + * @return Limited table or NULL on error + */ +TableData* lsh_limit(TableData *input, char **args); + +/** + * Case-insensitive substring search (strcasestr equivalent for Windows) + */ +char *my_strcasestr(const char *haystack, const char *needle); + +// Export the filter arrays for the shell +extern char *filter_str[]; +extern TableData* (*filter_func[]) (TableData*, char**); +extern int filter_count; + +#endif // FILTERS_H diff --git a/filters.o b/filters.o new file mode 100644 index 0000000000000000000000000000000000000000..4c0ee9a1048697b7064272181d1a9b12cad9beed GIT binary patch literal 27056 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 +#include +#include +#include // For stat + +/** + * Check if native fzf is installed on the system + * + * @return 1 if installed, 0 if not + */ +int is_fzf_installed(void) { + // Try to run fzf --version to check if it's installed + FILE *fp = popen("fzf --version 2>/dev/null", "r"); + if (fp == NULL) { + return 0; + } + + // Read output (if any) + char buffer[128]; + int has_output = (fgets(buffer, sizeof(buffer), fp) != NULL); + + // Close the process + pclose(fp); + + return has_output; +} + +/** + * Display instructions for installing fzf + */ +void show_fzf_install_instructions(void) { + printf("\nfzf is not installed on this system. To use this feature, install " + "fzf:\n\n"); + printf("Installation options:\n"); + printf("1. Using Git:\n"); + printf(" git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf\n"); + printf(" ~/.fzf/install\n\n"); + printf("2. Using Chocolatey (Windows):\n"); + printf(" choco install fzf\n\n"); + printf("3. Using Scoop (Windows):\n"); + printf(" scoop install fzf\n\n"); + printf("4. Download prebuilt binary from: " + "https://github.com/junegunn/fzf/releases\n\n"); + printf("After installation, restart your shell.\n"); +} + +/** + * Run fzf with files from the current directory + * + * @param preview Enable preview window if 1 + * @param args Additional arguments for fzf + * @return Selected filename or NULL if canceled + */ +char *run_native_fzf_files(int preview, char **args) { + // Check if fzf is installed + if (!is_fzf_installed()) { + show_fzf_install_instructions(); + return NULL; + } + + // Build the command + char command[1024] = "find . -type f -not -path \"*/\.*\" -printf \"%P\\n\" | fzf"; + + // Add proper keybindings for both navigation and search toggle + strcat(command, " --bind=\"ctrl-j:down,ctrl-k:up,/:toggle-search\""); + + // Add preview if requested + if (preview) { + strcat(command, " --preview=\"cat {}\""); + } + + // Add any additional arguments + if (args && args[1] != NULL) { + int i = 1; + while (args[i] != NULL) { + strcat(command, " "); + + // If the argument contains spaces, quote it + if (strchr(args[i], ' ') != NULL) { + strcat(command, "\""); + strcat(command, args[i]); + strcat(command, "\""); + } else { + strcat(command, args[i]); + } + + i++; + } + } + + // Redirect output to a temporary file to capture selection + char tempfile[PATH_MAX]; + strcpy(tempfile, "/tmp/fzf_result.txt"); + + // Append output redirection to the command + strcat(command, " > "); + strcat(command, tempfile); + + // Run the command + int result = system(command); + + // Check if user canceled (fzf returns non-zero) + if (result != 0) { + remove(tempfile); // Clean up temp file even on cancel + return NULL; + } + + // Read the selected filename from the temporary file + FILE *fp = fopen(tempfile, "r"); + if (!fp) { + remove(tempfile); + return NULL; + } + + // Read the selected line + char *selected = (char *)malloc(PATH_MAX); + if (!selected) { + fclose(fp); + remove(tempfile); + return NULL; + } + + if (fgets(selected, PATH_MAX, fp) == NULL) { + fclose(fp); + remove(tempfile); + free(selected); + return NULL; + } + + // Remove newline if present + size_t len = strlen(selected); + if (len > 0 && selected[len - 1] == '\n') { + selected[len - 1] = '\0'; + } + + // Close the file and delete it + fclose(fp); + remove(tempfile); + + return selected; +} + +/** + * Run fzf with all files and directories from the current directory + * + * @param recursive Search recursively if 1 + * @param args Additional arguments for fzf + * @return Selected path or NULL if canceled + */ +char *run_native_fzf_all(int recursive, char **args) { + // Check if fzf is installed + if (!is_fzf_installed()) { + show_fzf_install_instructions(); + return NULL; + } + + // Build the command using find + char command[1024]; + + if (recursive) { + strcpy(command, "find . -not -path \"*/\.*\" -printf \"%P\\n\" | fzf"); + } else { + strcpy(command, "find . -maxdepth 1 -not -path \"*/\.*\" -printf \"%P\\n\" | fzf"); + } + + // Add proper keybindings for both navigation and search toggle + strcat(command, " --bind=\"ctrl-j:down,ctrl-k:up,/:toggle-search\""); + + // Add preview window showing file info or directory contents + strcat(command, " --preview=\"if [ -d {} ]; then ls -la {}; else bat " + "--color=always {} 2>/dev/null || cat {} 2>/dev/null; fi\""); + + // Add any additional arguments + if (args && args[1] != NULL) { + int i = 1; + while (args[i] != NULL) { + if (strcmp(args[i], "-r") != 0 && strcmp(args[i], "--recursive") != 0) { + strcat(command, " "); + + // If the argument contains spaces, quote it + if (strchr(args[i], ' ') != NULL) { + strcat(command, "\""); + strcat(command, args[i]); + strcat(command, "\""); + } else { + strcat(command, args[i]); + } + } + i++; + } + } + + // Redirect output to a temporary file to capture selection + char tempfile[PATH_MAX]; + strcpy(tempfile, "/tmp/fzf_result.txt"); + + // Append output redirection to the command + strcat(command, " > "); + strcat(command, tempfile); + + // Run the command + int result = system(command); + + // Check if user canceled (fzf returns non-zero) + if (result != 0) { + remove(tempfile); // Clean up temp file even on cancel + return NULL; + } + + // Read the selected path from the temporary file + FILE *fp = fopen(tempfile, "r"); + if (!fp) { + remove(tempfile); + return NULL; + } + + // Read the selected line + char *selected = (char *)malloc(PATH_MAX); + if (!selected) { + fclose(fp); + remove(tempfile); + return NULL; + } + + if (fgets(selected, PATH_MAX, fp) == NULL) { + fclose(fp); + remove(tempfile); + free(selected); + return NULL; + } + + // Remove newline if present + size_t len = strlen(selected); + if (len > 0 && selected[len - 1] == '\n') { + selected[len - 1] = '\0'; + } + + // Close the file and delete it + fclose(fp); + remove(tempfile); + + return selected; +} + +/** + * Run fzf with command history + * + * @return Selected command or NULL if canceled + */ +char *run_native_fzf_history(void) { + // Check if fzf is installed + if (!is_fzf_installed()) { + show_fzf_install_instructions(); + return NULL; + } + + // Create a temporary file with command history + char tempfile_in[PATH_MAX]; + strcpy(tempfile_in, "/tmp/fzf_history.txt"); + + FILE *fp_in = fopen(tempfile_in, "w"); + if (!fp_in) { + return NULL; + } + + // Write history to temporary file + int num_to_display = + (history_count < HISTORY_SIZE) ? history_count : HISTORY_SIZE; + int start_idx; + + if (history_count <= HISTORY_SIZE) { + // Haven't filled the buffer yet + start_idx = 0; + } else { + // History buffer is full, start from the oldest command + start_idx = history_index; // Next slot to overwrite contains oldest command + } + + for (int i = 0; i < num_to_display; i++) { + int idx = (start_idx + i) % HISTORY_SIZE; + if (command_history[idx].command) { + fprintf(fp_in, "%s\n", command_history[idx].command); + } + } + + fclose(fp_in); + + // Create a temporary file for the result + char tempfile_out[PATH_MAX]; + strcpy(tempfile_out, "/tmp/fzf_result.txt"); + + // Build the command + char command[1024]; + sprintf(command, + "cat \"%s\" | fzf --tac --no-sort " + "--bind=\"ctrl-j:down,ctrl-k:up,/:toggle-search\" > \"%s\"", + tempfile_in, tempfile_out); + + // Run the command + int result = system(command); + + // Delete the input file + remove(tempfile_in); + + // Check if user canceled + if (result != 0) { + remove(tempfile_out); // Clean up temp file even on cancel + return NULL; + } + + // Read the selected command from the output file + FILE *fp_out = fopen(tempfile_out, "r"); + if (!fp_out) { + remove(tempfile_out); + return NULL; + } + + // Read the selected line + char *selected = (char *)malloc(PATH_MAX); + if (!selected) { + fclose(fp_out); + remove(tempfile_out); + return NULL; + } + + if (fgets(selected, PATH_MAX, fp_out) == NULL) { + fclose(fp_out); + remove(tempfile_out); + free(selected); + return NULL; + } + + // Remove newline if present + size_t len = strlen(selected); + if (len > 0 && selected[len - 1] == '\n') { + selected[len - 1] = '\0'; + } + + // Close and delete the output file + fclose(fp_out); + remove(tempfile_out); + + return selected; +} + +/** + * Check if a specific editor is available + * + * @param editor Name of the editor executable + * @return 1 if available, 0 if not + */ +int is_editor_available(const char *editor) { + char command[256]; + snprintf(command, sizeof(command), "%s --version >/dev/null 2>&1", editor); + return (system(command) == 0); +} + +/** + * Open a file in the best available editor in the current terminal + * + * @param file_path Path to the file to open + * @param line_number Optional line number to jump to (0 to ignore) + * @return 1 if successful, 0 if failed + */ +int open_in_best_editor(const char *file_path, int line_number) { + char command[2048] = {0}; + int success = 0; + + // Try to detect available editors (in order of preference) + if (is_editor_available("nvim")) { + // Neovim is available - construct command with +line_number + if (line_number > 0) { + snprintf(command, sizeof(command), "nvim +%d \"%s\"", line_number, + file_path); + } else { + snprintf(command, sizeof(command), "nvim \"%s\"", file_path); + } + success = 1; + } else if (is_editor_available("vim")) { + // Vim is available + if (line_number > 0) { + snprintf(command, sizeof(command), "vim +%d \"%s\"", line_number, + file_path); + } else { + snprintf(command, sizeof(command), "vim \"%s\"", file_path); + } + success = 1; + } else if (is_editor_available("nano")) { + // Try nano if available + snprintf(command, sizeof(command), "nano \"%s\"", file_path); + success = 1; + } else if (is_editor_available("code")) { + // VSCode in the terminal if possible + if (line_number > 0) { + snprintf(command, sizeof(command), "code -g \"%s:%d\" -r", file_path, + line_number); + } else { + snprintf(command, sizeof(command), "code \"%s\" -r", file_path); + } + success = 1; + } else if (is_editor_available("notepad")) { + // Notepad as a last resort (will still open in a new window) + snprintf(command, sizeof(command), "notepad \"%s\"", file_path); + success = 1; + } + + if (success) { + // Clear the screen before launching the editor + system("clear"); + + // Execute the command directly in the current terminal + system(command); + + // Return directly to prompt without requiring key press + return 1; + } else { + // No suitable editor found + printf("No compatible editor (neovim, vim, nano or VSCode) found.\n"); + return 0; + } +} + +/** + * Command handler for the fzf command + * + * @param args Command arguments + * @return 1 to continue shell execution, 0 to exit shell + */ +int lsh_fzf_native(char **args) { + // Check if fzf is installed + if (!is_fzf_installed()) { + show_fzf_install_instructions(); + return 1; + } + + // Parse options + int recursive = 0; + int mode = 0; // 0 = all, 1 = files only, 2 = history + int no_open = 0; // Don't open files automatically if set + int arg_index = 1; + + if (args[arg_index] && strcmp(args[arg_index], "--help") == 0) { + printf("Usage: fzf [options] [pattern]\n"); + printf("Interactive fuzzy finder.\n"); + printf("Options:\n"); + printf(" -r, --recursive Search directories recursively\n"); + printf(" -f, --files Search only files (not directories)\n"); + printf(" -h, --history Search command history\n"); + printf(" --no-open Don't automatically open selected files\n"); + printf("\nControls:\n"); + printf(" Ctrl+j/Ctrl+k Move down/up (vim-style navigation)\n"); + printf(" Type directly To search (default mode)\n"); + printf(" / Toggle search mode (allows searching for 'j' " + "and 'k')\n"); + printf(" Enter Select item (and open file)\n"); + printf(" Ctrl+C/Esc Cancel\n"); + printf(" ? Toggle preview window\n"); + return 1; + } + + // Process options + while (args[arg_index] != NULL && args[arg_index][0] == '-') { + if (strcmp(args[arg_index], "-r") == 0 || + strcmp(args[arg_index], "--recursive") == 0) { + recursive = 1; + arg_index++; + } else if (strcmp(args[arg_index], "-f") == 0 || + strcmp(args[arg_index], "--files") == 0) { + mode = 1; // Files only + arg_index++; + } else if (strcmp(args[arg_index], "-h") == 0 || + strcmp(args[arg_index], "--history") == 0) { + mode = 2; // History + arg_index++; + } else if (strcmp(args[arg_index], "--no-open") == 0) { + no_open = 1; + arg_index++; + } else { + break; // Unknown option, treat as pattern + } + } + + // Run fzf based on the selected mode + char *result = NULL; + + if (mode == 2) { + // History mode + result = run_native_fzf_history(); + } else if (mode == 1) { + // Files only mode + result = run_native_fzf_files(1, args); + } else { + // All files and directories + result = run_native_fzf_all(recursive, args); + } + + // Handle the result + if (result) { + if (mode == 2) { + // Execute the selected command from history + printf("Executing: %s\n", result); + + // Parse and execute the command + char *cmd_copy = strdup(result); + if (cmd_copy) { + char **cmd_args = lsh_split_line(cmd_copy); + lsh_execute(cmd_args); + + // Clean up + free(cmd_args); + free(cmd_copy); + } + } else { + // File or directory selected + + // Check if it's a regular file (not a directory) + struct stat file_stat; + int stat_result = stat(result, &file_stat); + + if (stat_result == 0) { + int is_directory = S_ISDIR(file_stat.st_mode); + + if (is_directory) { + // It's a directory, just print it + printf("Selected directory: %s\n", result); + + // Optionally change to that directory + printf("Do you want to change to this directory? (y/n): "); + char response = getchar(); + // Clear input buffer + while (getchar() != '\n') + ; + + if (response == 'y' || response == 'Y') { + chdir(result); + printf("Changed directory to: %s\n", result); + } + } else { + // It's a file + printf("Selected file: %s\n", result); + + // Open in editor if allowed + if (!no_open) { + int success = open_in_best_editor(result, 0); + if (success) { + printf("File opened in editor.\n"); + } + } + } + } else { + // Could not determine file type, just print the path + printf("Selected: %s\n", result); + } + } + + free(result); + } else { + printf("No selection made.\n"); + } + + return 1; +} diff --git a/fzf_native.h b/fzf_native.h new file mode 100644 index 0000000..d893acd --- /dev/null +++ b/fzf_native.h @@ -0,0 +1,57 @@ +/** + * fzf_native.h + * Header for native fzf command-line fuzzy finder wrapper + */ + +#ifndef FZF_NATIVE_H +#define FZF_NATIVE_H + +#include "builtins.h" +#include "common.h" + +/** + * Check if native fzf is installed on the system + * + * @return 1 if installed, 0 if not + */ +int is_fzf_installed(void); + +/** + * Display instructions for installing fzf + */ +void show_fzf_install_instructions(void); + +/** + * Run fzf with files from the current directory + * + * @param preview Enable preview window if 1 + * @param args Additional arguments for fzf + * @return Selected filename or NULL if canceled + */ +char *run_native_fzf_files(int preview, char **args); + +/** + * Run fzf with all files and directories from the current directory + * + * @param recursive Search recursively if 1 + * @param args Additional arguments for fzf + * @return Selected path or NULL if canceled + */ +char *run_native_fzf_all(int recursive, char **args); + +/** + * Run fzf with command history + * + * @return Selected command or NULL if canceled + */ +char *run_native_fzf_history(void); + +/** + * Command handler for the fzf command + * + * @param args Command arguments + * @return 1 to continue shell execution, 0 to exit shell + */ +int lsh_fzf_native(char **args); + +#endif // FZF_NATIVE_H diff --git a/fzf_native.o b/fzf_native.o new file mode 100644 index 0000000000000000000000000000000000000000..695dd290590288fe8ffe6401c5d22fd150148757 GIT binary patch literal 26152 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 literal 0 HcmV?d00001 diff --git a/git_integration.c b/git_integration.c new file mode 100644 index 0000000..723af24 --- /dev/null +++ b/git_integration.c @@ -0,0 +1,154 @@ +/** + * git_integration.c + * Implementation of Git repository detection and information + */ + +#include "git_integration.h" +#include +#include +#include +#include + +/** + * Initialize Git integration + */ +void init_git_integration(void) { + // No initialization needed for Linux +} + +/** + * Check if the current directory is in a Git repository and get branch info + */ +int get_git_branch(char *branch_name, size_t buffer_size, int *is_dirty) { + char git_dir[PATH_MAX] = ""; + char cmd[PATH_MAX] = ""; + FILE *fp; + int status = 0; + + // Initialize output parameters + if (branch_name && buffer_size > 0) { + branch_name[0] = '\0'; + } + if (is_dirty) { + *is_dirty = 0; + } + + // First check if .git directory exists (faster than running git command) + strcpy(git_dir, ".git"); + struct stat st; + if (stat(git_dir, &st) != 0 || !S_ISDIR(st.st_mode)) { + // Try to find .git in parent directories + // (Note: this is more complex, simplified here) + return 0; + } + + // Get current branch + if (branch_name && buffer_size > 0) { + strcpy(cmd, "git rev-parse --abbrev-ref HEAD 2>/dev/null"); + fp = popen(cmd, "r"); + if (fp) { + if (fgets(branch_name, buffer_size, fp) != NULL) { + // Remove trailing newline + char *newline = strchr(branch_name, '\n'); + if (newline) { + *newline = '\0'; + } + status = 1; + } + pclose(fp); + } + } + + // Check if working directory is dirty + if (is_dirty && status) { + strcpy(cmd, "git status --porcelain 2>/dev/null"); + fp = popen(cmd, "r"); + if (fp) { + char ch; + if ((ch = fgetc(fp)) != EOF) { + *is_dirty = 1; + } + pclose(fp); + } + } + + return status; +} + +/** + * Get the name of the Git repository + */ +int get_git_repo_name(char *repo_name, size_t buffer_size) { + if (!repo_name || buffer_size == 0) { + return 0; + } + + repo_name[0] = '\0'; + + char cmd[PATH_MAX] = "git rev-parse --show-toplevel 2>/dev/null"; + FILE *fp = popen(cmd, "r"); + if (!fp) { + return 0; + } + + char path[PATH_MAX]; + if (fgets(path, sizeof(path), fp) == NULL) { + pclose(fp); + return 0; + } + pclose(fp); + + // Remove trailing newline + char *newline = strchr(path, '\n'); + if (newline) { + *newline = '\0'; + } + + // Extract the directory name from the full path + char *last_slash = strrchr(path, '/'); + if (last_slash) { + strncpy(repo_name, last_slash + 1, buffer_size - 1); + repo_name[buffer_size - 1] = '\0'; + return 1; + } + + return 0; +} + +/** + * Get Git status for the current repository + */ +char *get_git_status(void) { + char branch_name[100] = ""; + int is_dirty = 0; + char repo_name[100] = ""; + + // Check if we're in a Git repo and get branch info + if (!get_git_branch(branch_name, sizeof(branch_name), &is_dirty)) { + return NULL; // Not in a Git repo + } + + // Get repo name + get_git_repo_name(repo_name, sizeof(repo_name)); + + // Format status string + char *status = malloc(256); + if (!status) { + return NULL; + } + + if (strlen(repo_name) > 0) { + sprintf(status, "%s%s (%s%s%s)", + repo_name, + branch_name[0] ? ":" : "", + branch_name, + is_dirty ? " *" : "", + ""); + } else { + sprintf(status, "%s%s", + branch_name, + is_dirty ? " *" : ""); + } + + return status; +} \ No newline at end of file diff --git a/git_integration.h b/git_integration.h new file mode 100644 index 0000000..84453d1 --- /dev/null +++ b/git_integration.h @@ -0,0 +1,43 @@ +/** + * git_integration.h + * Functions for Git repository detection and information + */ + +#ifndef GIT_INTEGRATION_H +#define GIT_INTEGRATION_H + +#include "common.h" + +/** + * Initialize Git integration + */ +void init_git_integration(void); + +/** + * Check if the current directory is in a Git repository and get branch info + * + * @param branch_name Buffer to store branch name if found + * @param buffer_size Size of the branch_name buffer + * @param is_dirty Pointer to store dirty status flag (1 if repo has changes) + * @return 1 if in a Git repo, 0 otherwise + */ +int get_git_branch(char *branch_name, size_t buffer_size, int *is_dirty); + +/** + * Get the name of the Git repository + * + * @param repo_name Buffer to store repo name if found + * @param buffer_size Size of the repo_name buffer + * @return 1 if name was retrieved, 0 otherwise + */ +int get_git_repo_name(char *repo_name, size_t buffer_size); + +/** + * Get Git status for the current repository + * + * @return A string with the Git status or NULL if not in a repo + * (caller must free the returned string) + */ +char *get_git_status(void); + +#endif // GIT_INTEGRATION_H \ No newline at end of file diff --git a/git_integration.o b/git_integration.o new file mode 100644 index 0000000000000000000000000000000000000000..98e2aa87f4d4ab2142c55b2d74d8d80c873d2b64 GIT binary patch literal 11296 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 literal 0 HcmV?d00001 diff --git a/grep.c b/grep.c new file mode 100644 index 0000000..fca71ea --- /dev/null +++ b/grep.c @@ -0,0 +1,54 @@ +/** + * grep.c + * Simple implementation of text searching for Linux + */ + +#include "grep.h" +#include "builtins.h" +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * Simple grep implementation + */ +int lsh_actual_grep(char **args) { + if (args[1] == NULL) { + printf("Usage: grep [pattern] [file...]\n"); + return 1; + } + + // Use the system's grep command + char command[1024] = "grep "; + + // Add the pattern (first argument) + strcat(command, "\""); + strcat(command, args[1]); + strcat(command, "\""); + + // Add any additional files specified + for (int i = 2; args[i] != NULL; i++) { + strcat(command, " "); + strcat(command, args[i]); + } + + // If no files specified, use all files in current directory + if (args[2] == NULL) { + strcat(command, " ."); + } + + // Execute the grep command + return system(command); +} + +/** + * Wrapper for grep + */ +int lsh_grep(char **args) { + return lsh_actual_grep(args); +} \ No newline at end of file diff --git a/grep.h b/grep.h new file mode 100644 index 0000000..2dcdda4 --- /dev/null +++ b/grep.h @@ -0,0 +1,28 @@ +/** + * grep.h + * Header for fast text searching in files with fuzzy matching capabilities + */ + +#ifndef GREP_H +#define GREP_H + +#include "common.h" + +/** + * Command handler for the "grep" command + * + * Usage: grep [options] pattern [file/directory] + * Options: + * -n, --line-numbers Show line numbers + * -i, --ignore-case Ignore case distinctions + * -r, --recursive Search directories recursively + * -f, --fuzzy Use fuzzy matching instead of exact + * --file Specify files/directories to search (otherwise searches + * current dir) + * + * @param args Command arguments + * @return 1 to continue shell execution, 0 to exit shell + */ +int lsh_grep(char **args); + +#endif // GREP_H diff --git a/grep.o b/grep.o new file mode 100644 index 0000000000000000000000000000000000000000..75b6ceb1a6797da41f7614be66a2287014e25675 GIT binary patch literal 4944 zcmbtW3se->8NSQ%5?`wl5G7$keSqM0SrsC_Rt;n#nnVObLUbQ6fR$Hv7X$GaL4=44 zm8g3{BC#PcR%2?#rl+V0E)PXkv`H&e)1GRL8cay5p*caZrT3q`KaAtjoYVg2%-s8b z|8xHP&%Jj`+{$XJas5#a-c}AMU*_=TZG~${@`FENRGcIivQHdALgr>lFJ!i*@B4Tv&?o9N*+i+g~G~i3_pa7 zwJ^wzz&QO-Cz9wivU7SWaA*v;w2m zDwy-ua%q|Ca|E?oy>_Tq*0H9+-YKfHnKBFp!EoI`Jfc;PpDXeH`<&2ARl&X7j(5uE z&H1(G+4OSXWntSNuUcuCUKOd@@y6It-;|c5ZK`Ww%WB(`MunP7J!jS~*!xzyKmSvu z>1IleZ{T*rKBrHjS=H8Ap3qR@J88`{pM>V%1z#zZXDwXu=jxi{ljd;FxEgziuq}MN zVcV?0Hx%Jn`-TKwu2Fa9U=KP zL+v{Ag>%Qv$vBp-0D<+_nq^vWgq8kT|98Xe(d~}uJ(kBFQ)J5eJMrJ zm-zGU)m;Ozi}E(=7XNds;hD{aQAwA-t~hkJXT!NAH~sr6Cj2`(WzR+L?$2uvHH040 zZ+pVhMVi_ZCeDncnL%R`;w!%Kbp_K!U}!|aC59khRClt);cz$|%?8E(prD{FeRsBo z#jD0ga=&jQUMqFcOGYdG44#udS}~@sK1b;?>%C`J#wMrpL`Cb=Ghd}|y5Nl6XSQh*>u9!>=0r%h!2lX8y2>@5x9N&O`=Wzg+*$j__Mi z#x1X8grt3c%4c_=@1KLRv`62cGJe{Q+qU0SUyI2}tSZ@U_(fPq{lJxPigpKfC3JP4 zNJ)&jcd_Tdo5`J{zi58p4nK(oY?X~MDYIlBg=eFJsV;Qut#*wZfZ|^>|4Ed4S8z$@>nkHsb`YIxv05ntvZU+ zYP9n-T1^b0`!eC^13NBNpxvTy0EYEc$asG$15&)2NEAgX#ndrAzBN=im}2k%od)Bj z<5U$M%g1^v9SW)<$`*=JLZ-lo@??;XOyJ6s+!=JIp&ZKcL8(&wng=o9l*IdCP{iG5 zpd_P5(3c!`5)CC8C*fRE@H|nHr&t?`O{R~^rSic0(Gl=zBj6Du;Mx)Jn&De`UZV^_6B{X zaea3XtJo1BB}b;axku2$NZ^LG&Z-`X~twKBh7r*9G%|3lvbiYY_clOn_F&@C?Q$ z$?%j6cUltTX;U z*JS#)8GlEHW4*9H(GOE269Axu^+!LP41e9FMl=jZKVLE&*BbmluOs1JgZhYvvI*!z zzrnr%G{ZFv^&!?rBg22j_<1t?WyZ(K@FK=b`wiljGW=;a%JbwH?mCyM$m7F}7JUA%_OSnfPkA_w0UVV{3G+v6F`bAx$pkuP z-;IiFl&O*V6n9rY9UK~z3YZ_LAFL7DWBpc8%w7D+tRM%dTuNw<82rcbnu4r}+2j9> z`f}Y=DsY$oQ8+v)p*`depM>!-f7ln?<$s&S|1FhE3GETfp%ZuUud?_DnIgmo2< +#include +#include +#include +#include +#include +#include + +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + +/** + * Check if a command is valid + * + * @param cmd The command to check + * @return 1 if valid, 0 if not + */ +int is_valid_command(const char *cmd) { + if (!cmd || cmd[0] == '\0') { + return 0; // Empty command is not valid + } + + // Extract just the command part (before any spaces) + char command_part[LSH_RL_BUFSIZE]; + int i = 0; + while (cmd[i] && !isspace(cmd[i]) && i < LSH_RL_BUFSIZE - 1) { + command_part[i] = cmd[i]; + i++; + } + command_part[i] = '\0'; + + // Check built-in commands + for (int i = 0; i < lsh_num_builtins(); i++) { + if (strcasecmp(command_part, builtin_str[i]) == 0) { + return 1; + } + } + + // Check aliases + AliasEntry *alias = find_alias(command_part); + if (alias) { + return 1; + } + + // Check if it's an executable in PATH + // We'll use a simplified approach - check if the file exists and is executable + struct stat st; + char path_buffer[PATH_MAX]; + + // First check if it's an absolute or relative path + if (strchr(command_part, '/')) { + // Path contains slashes, check if file exists and is executable + if (stat(command_part, &st) == 0 && (st.st_mode & S_IXUSR)) { + return 1; + } + } else { + // Check in current directory + snprintf(path_buffer, PATH_MAX, "./%s", command_part); + if (stat(path_buffer, &st) == 0 && (st.st_mode & S_IXUSR)) { + return 1; + } + + // Check in PATH directories + char *path_env = getenv("PATH"); + if (!path_env) { + return 0; // No PATH defined + } + + char *path_copy = strdup(path_env); + if (!path_copy) { + return 0; // Memory allocation error + } + + char *token, *rest = path_copy; + while ((token = strtok_r(rest, ":", &rest))) { + // Construct full path to check + snprintf(path_buffer, PATH_MAX, "%s/%s", token, command_part); + if (stat(path_buffer, &st) == 0 && (st.st_mode & S_IXUSR)) { + free(path_copy); + return 1; + } + } + free(path_copy); + } + + return 0; // Command not found +} + +/** + * Read a key from the terminal + * + * Handles special keys and escape sequences + */ +int read_key(void) { + unsigned char c; + int nread; + char seq[6]; + + // Define local constants for special keys + // We avoid modifying common.h by using local constants + #define LOCAL_KEY_SHIFT_ENTER 1010 + + // Read a character + while ((nread = read(STDIN_FILENO, &c, 1)) != 1) { + if (nread == -1 && errno != EAGAIN) + return -1; + } + + // Handle carriage return (CR) as enter + if (c == 13) { + return KEY_ENTER; + } + + // Handle escape sequences for arrow keys and other special keys + if (c == KEY_ESCAPE) { + // Read up to 5 additional chars + int i = 0; + fd_set readfds; + struct timeval timeout; + + FD_ZERO(&readfds); + FD_SET(STDIN_FILENO, &readfds); + timeout.tv_sec = 0; + timeout.tv_usec = 50000; // 50ms timeout + + // Try to read the sequence with timeout to avoid blocking + while (i < 5) { + int select_result = select(STDIN_FILENO + 1, &readfds, NULL, NULL, &timeout); + if (select_result <= 0) break; // Timeout or error + + if (read(STDIN_FILENO, &seq[i], 1) != 1) break; + i++; + + // Check for known sequences + if (i >= 2 && seq[0] == '[') { + switch (seq[1]) { + case 'A': return KEY_UP; + case 'B': return KEY_DOWN; + case 'C': return KEY_RIGHT; + case 'D': return KEY_LEFT; + } + } + + // Check for Shift+Enter sequence (varies by terminal, try common forms) + // Note: These may vary widely between terminals + if (i >= 3) { + // xterm/vte: ESC [ 13 ; 2 ~ + if (seq[0] == '[' && seq[1] == '1' && seq[2] == '3' && i >= 5 && seq[3] == ';' && seq[4] == '2') { + return LOCAL_KEY_SHIFT_ENTER; + } + + // Another common sequence for Shift+Enter in some terminals + if (seq[0] == 'O' && seq[1] == '2' && seq[2] == 'M') { + return LOCAL_KEY_SHIFT_ENTER; + } + } + } + + return KEY_ESCAPE; + } + + return c; +} + +/** + * Read a line of input from the user + * + * @return The line read from stdin + */ +char *lsh_read_line(void) { + int bufsize = LSH_RL_BUFSIZE; + int position = 0; + char *buffer = malloc(sizeof(char) * bufsize); + int c; + int history_position = -1; + int show_suggestions = 0; + + // Suggestion state + static int has_suggestion = 0; + static int suggestion_index = 0; + static char **suggestions = NULL; + static int suggestion_count = 0; + static char full_suggestion[LSH_RL_BUFSIZE] = {0}; + static int prefix_start = 0; + + // Define colors for suggestions + #define SUGGESTION_COLOR "\033[2;37m" // Dim white color for suggestions + #define COUNTER_COLOR "\033[0;36m" // Cyan color for the counter + #define RESET_COLOR "\033[0m" + + if (!buffer) { + fprintf(stderr, "lsh: allocation error\n"); + exit(EXIT_FAILURE); + } + + // Clear the buffer + buffer[0] = '\0'; + + // Display prompt + printf("\033[1;32m➜\033[0m "); + fflush(stdout); + + // Function to check if current input exactly matches current suggestion + int is_complete_match() { + if (!has_suggestion || suggestion_count == 0) { + return 0; // No suggestion to compare with + } + + // If we're typing a command (not an argument) + if (prefix_start == 0) { + // Check if buffer exactly matches the current suggestion + return (strcasecmp(buffer, suggestions[suggestion_index]) == 0); + } else { + // We're completing an argument + // Check if the part after the last space exactly matches the suggestion + char *arg_part = buffer + prefix_start; + return (strcasecmp(arg_part, suggestions[suggestion_index]) == 0); + } + } + + // Function to update and display suggestions + void update_suggestions() { + // Free previous suggestions if any + if (suggestions) { + for (int i = 0; i < suggestion_count; i++) { + if (suggestions[i]) free(suggestions[i]); + } + free(suggestions); + suggestions = NULL; + suggestion_count = 0; + } + + has_suggestion = 0; + + // Parse command line + prefix_start = 0; + + // Find the last space to determine where the prefix starts + char *last_space = strrchr(buffer, ' '); + if (last_space) { + // We have a command and partial argument + prefix_start = (last_space - buffer) + 1; + + // Skip additional spaces + while (buffer[prefix_start] == ' ' && buffer[prefix_start] != '\0') { + prefix_start++; + } + } else { + // Just a command, no arguments + prefix_start = 0; + } + + // Build list of suggestions + suggestions = NULL; + suggestion_count = 0; + + // Get command or file suggestions based on context + if (!last_space) { + // Command suggestions + // First count how many we'll need + for (int i = 0; i < lsh_num_builtins(); i++) { + if (strncasecmp(builtin_str[i], buffer, strlen(buffer)) == 0) { + suggestion_count++; + } + } + + // Add alias count - rough estimate + int alias_count; + char **aliases = get_alias_names(&alias_count); + if (aliases) { + for (int i = 0; i < alias_count; i++) { + if (strncasecmp(aliases[i], buffer, strlen(buffer)) == 0) { + suggestion_count++; + } + } + + // Free alias names, we'll get them again + for (int i = 0; i < alias_count; i++) { + free(aliases[i]); + } + free(aliases); + } + + // Allocate suggestions array + if (suggestion_count > 0) { + suggestions = (char**)malloc(suggestion_count * sizeof(char*)); + if (!suggestions) { + fprintf(stderr, "Memory allocation error\n"); + suggestion_count = 0; + } else { + // Initialize all entries to NULL + for (int i = 0; i < suggestion_count; i++) { + suggestions[i] = NULL; + } + } + } + + // Now fill the suggestions array + int idx = 0; + + // Add builtin commands + for (int i = 0; i < lsh_num_builtins() && idx < suggestion_count; i++) { + if (strncasecmp(builtin_str[i], buffer, strlen(buffer)) == 0) { + suggestions[idx++] = strdup(builtin_str[i]); + } + } + + // Add aliases + aliases = get_alias_names(&alias_count); + if (aliases) { + for (int i = 0; i < alias_count && idx < suggestion_count; i++) { + if (strncasecmp(aliases[i], buffer, strlen(buffer)) == 0) { + suggestions[idx++] = strdup(aliases[i]); + } + } + + // Free alias names + for (int i = 0; i < alias_count; i++) { + free(aliases[i]); + } + free(aliases); + } + + // Update actual suggestion count in case we got fewer than expected + suggestion_count = idx; + } else { + // File/directory suggestions + char prefix[PATH_MAX] = ""; + char dir_path[PATH_MAX] = "."; + char name_prefix[PATH_MAX] = ""; + + if (buffer[prefix_start] != '\0') { + strncpy(prefix, &buffer[prefix_start], sizeof(prefix) - 1); + prefix[sizeof(prefix) - 1] = '\0'; + + // Split path into directory part and name prefix part + char *last_slash = strrchr(prefix, '/'); + if (last_slash) { + // Path contains a directory part + int dir_len = last_slash - prefix; + strncpy(dir_path, prefix, dir_len); + dir_path[dir_len] = '\0'; + + // Handle absolute path vs. relative path with subdirectories + if (dir_len == 0) { + // Handle case where path starts with '/' + strcpy(dir_path, "/"); + } + + // Extract the name prefix part (after the last slash) + strncpy(name_prefix, last_slash + 1, sizeof(name_prefix) - 1); + name_prefix[sizeof(name_prefix) - 1] = '\0'; + } else { + // No directory part, just a name prefix + strncpy(name_prefix, prefix, sizeof(name_prefix) - 1); + name_prefix[sizeof(name_prefix) - 1] = '\0'; + } + } + + // Count matching files and directories + DIR *dir = opendir(dir_path); + if (dir) { + struct dirent *entry; + + // First count the number of matching entries + while ((entry = readdir(dir)) != NULL) { + // Skip "." and ".." if there's a name prefix + if (name_prefix[0] != '\0' && + (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)) { + continue; + } + + if (strncasecmp(entry->d_name, name_prefix, strlen(name_prefix)) == 0) { + suggestion_count++; + } + } + + rewinddir(dir); + + // Allocate suggestions array + if (suggestion_count > 0) { + suggestions = (char**)malloc(suggestion_count * sizeof(char*)); + if (!suggestions) { + fprintf(stderr, "Memory allocation error\n"); + suggestion_count = 0; + } else { + // Initialize all entries to NULL + for (int i = 0; i < suggestion_count; i++) { + suggestions[i] = NULL; + } + } + } + + // Fill the suggestions array + int idx = 0; + while ((entry = readdir(dir)) != NULL && idx < suggestion_count) { + // Skip "." and ".." if there's a name prefix + if (name_prefix[0] != '\0' && + (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)) { + continue; + } + + if (strncasecmp(entry->d_name, name_prefix, strlen(name_prefix)) == 0) { + // Create the full path suggestion + char full_path[PATH_MAX * 2]; + + if (strcmp(dir_path, ".") == 0) { + strncpy(full_path, entry->d_name, sizeof(full_path) - 1); + } else if (dir_path[0] == '/' && dir_path[1] == '\0') { + snprintf(full_path, sizeof(full_path) - 1, "/%s", entry->d_name); + } else { + snprintf(full_path, sizeof(full_path) - 1, "%s/%s", dir_path, entry->d_name); + } + + // Check if it's a directory and add trailing slash if needed + struct stat st; + char check_path[PATH_MAX * 2]; + + if (dir_path[0] == '/') { + // Absolute path + snprintf(check_path, sizeof(check_path) - 1, "%s/%s", dir_path, entry->d_name); + } else { + // Relative path + snprintf(check_path, sizeof(check_path) - 1, "%s/%s", dir_path, entry->d_name); + } + + if (stat(check_path, &st) == 0 && S_ISDIR(st.st_mode)) { + strncat(full_path, "/", sizeof(full_path) - strlen(full_path) - 1); + } + + suggestions[idx++] = strdup(full_path); + } + } + + // Update actual suggestion count + suggestion_count = idx; + + closedir(dir); + } + } + + // If we have suggestions, use the first one + if (suggestion_count > 0) { + has_suggestion = 1; + suggestion_index = 0; + + // Create the full suggestion string that Enter would accept + if (prefix_start > 0) { + // We're completing an argument + strncpy(full_suggestion, buffer, prefix_start); + full_suggestion[prefix_start] = '\0'; + strncat(full_suggestion, suggestions[suggestion_index], + sizeof(full_suggestion) - strlen(full_suggestion) - 1); + } else { + // We're completing a command + strncpy(full_suggestion, suggestions[suggestion_index], sizeof(full_suggestion) - 1); + } + full_suggestion[sizeof(full_suggestion) - 1] = '\0'; + + // Determine what part should be in normal text and what part in suggestion color + char current_text[LSH_RL_BUFSIZE] = ""; + char suggestion_text[LSH_RL_BUFSIZE] = ""; + + strncpy(current_text, buffer, position); + current_text[position] = '\0'; + + // Extract just the suggestion part (after what user typed) + int current_len = 0; + + if (prefix_start > 0) { + char current_arg[LSH_RL_BUFSIZE] = ""; + strncpy(current_arg, &buffer[prefix_start], position - prefix_start); + current_arg[position - prefix_start] = '\0'; + current_len = strlen(current_arg); + + if (current_len > 0) { + // Find where the current argument ends in the suggestion + char *suggestion_part = suggestions[suggestion_index]; + if (strncasecmp(suggestion_part, current_arg, current_len) == 0) { + strncpy(suggestion_text, suggestion_part + current_len, + sizeof(suggestion_text) - 1); + } + } else { + // Use the entire suggestion + strncpy(suggestion_text, suggestions[suggestion_index], + sizeof(suggestion_text) - 1); + } + } else { + // Completing a command + if (strlen(buffer) <= strlen(suggestions[suggestion_index]) && + strncasecmp(suggestions[suggestion_index], buffer, strlen(buffer)) == 0) { + strncpy(suggestion_text, + suggestions[suggestion_index] + strlen(buffer), + sizeof(suggestion_text) - 1); + } + } + + // If there's no suggestion text (exact match), then don't show suggestion + if (strlen(suggestion_text) == 0) { + // Clear the current line + printf("\r\033[K"); + + // Display prompt and current text without suggestion + printf("\033[1;32m➜\033[0m %s", buffer); + fflush(stdout); + } else { + // Clear the current line + printf("\r\033[K"); + + // Display prompt and current text + printf("\033[1;32m➜\033[0m %s", current_text); + + // Display the suggestion part in dim color + printf("%s%s%s", SUGGESTION_COLOR, suggestion_text, RESET_COLOR); + + // Show counter for which suggestion we're on + if (suggestion_count > 1) { + printf(" %s(%d/%d)%s", COUNTER_COLOR, suggestion_index + 1, suggestion_count, RESET_COLOR); + + // Move cursor back to end of actual input (including the counter) + char counter_str[20]; + snprintf(counter_str, sizeof(counter_str), " (%d/%d)", suggestion_index + 1, suggestion_count); + int counter_len = strlen(counter_str); + int suggestion_len = strlen(suggestion_text); + + for (int i = 0; i < suggestion_len + counter_len; i++) { + printf("\b"); + } + } else { + // Just move cursor back to end of actual input + int suggestion_len = strlen(suggestion_text); + for (int i = 0; i < suggestion_len; i++) { + printf("\b"); + } + } + + fflush(stdout); + } + } else { + // No suggestions, just redraw the current line + printf("\r\033[K\033[1;32m➜\033[0m %s", buffer); + fflush(stdout); + } + } + + // Function to display the current suggestion (used after tab cycling) + void display_current_suggestion() { + if (has_suggestion && suggestion_count > 0) { + // Create the full suggestion string + if (prefix_start > 0) { + // We're completing an argument + strncpy(full_suggestion, buffer, prefix_start); + full_suggestion[prefix_start] = '\0'; + strncat(full_suggestion, suggestions[suggestion_index], + sizeof(full_suggestion) - strlen(full_suggestion) - 1); + } else { + // We're completing a command + strncpy(full_suggestion, suggestions[suggestion_index], sizeof(full_suggestion) - 1); + } + full_suggestion[sizeof(full_suggestion) - 1] = '\0'; + + // Determine what part should be in normal text and what part in suggestion color + char current_text[LSH_RL_BUFSIZE] = ""; + char suggestion_text[LSH_RL_BUFSIZE] = ""; + + strncpy(current_text, buffer, position); + current_text[position] = '\0'; + + // Extract just the suggestion part (after what user typed) + int current_len = 0; + + if (prefix_start > 0) { + char current_arg[LSH_RL_BUFSIZE] = ""; + strncpy(current_arg, &buffer[prefix_start], position - prefix_start); + current_arg[position - prefix_start] = '\0'; + current_len = strlen(current_arg); + + if (current_len > 0) { + // Find where the current argument ends in the suggestion + char *suggestion_part = suggestions[suggestion_index]; + if (strncasecmp(suggestion_part, current_arg, current_len) == 0) { + strncpy(suggestion_text, suggestion_part + current_len, + sizeof(suggestion_text) - 1); + } + } else { + // Use the entire suggestion + strncpy(suggestion_text, suggestions[suggestion_index], + sizeof(suggestion_text) - 1); + } + } else { + // Completing a command + if (strlen(buffer) <= strlen(suggestions[suggestion_index]) && + strncasecmp(suggestions[suggestion_index], buffer, strlen(buffer)) == 0) { + strncpy(suggestion_text, + suggestions[suggestion_index] + strlen(buffer), + sizeof(suggestion_text) - 1); + } + } + + // Clear the current line + printf("\r\033[K"); + + // Display prompt and current text + printf("\033[1;32m➜\033[0m %s", current_text); + + // Display the suggestion part in dim color + printf("%s%s%s", SUGGESTION_COLOR, suggestion_text, RESET_COLOR); + + // Show counter for which suggestion we're on + if (suggestion_count > 1) { + printf(" %s(%d/%d)%s", COUNTER_COLOR, suggestion_index + 1, suggestion_count, RESET_COLOR); + + // Move cursor back to end of actual input (including the counter) + char counter_str[20]; + snprintf(counter_str, sizeof(counter_str), " (%d/%d)", suggestion_index + 1, suggestion_count); + int counter_len = strlen(counter_str); + int suggestion_len = strlen(suggestion_text); + + for (int i = 0; i < suggestion_len + counter_len; i++) { + printf("\b"); + } + } else { + // Just move cursor back to end of actual input + int suggestion_len = strlen(suggestion_text); + for (int i = 0; i < suggestion_len; i++) { + printf("\b"); + } + } + + fflush(stdout); + } + } + + // Flag to track if we're in suggestion mode or execution mode + int suggestion_active = 1; // Start in suggestion mode + + while (1) { + c = read_key(); + + if (c == KEY_ENTER || c == '\n' || c == '\r') { + // Check if we have a visible suggestion (not an exact match) + if (has_suggestion && suggestion_count > 0) { + // Extract just the suggestion part to see if there's anything to complete + char suggestion_text[LSH_RL_BUFSIZE] = ""; + + if (prefix_start > 0) { + char current_arg[LSH_RL_BUFSIZE] = ""; + strncpy(current_arg, &buffer[prefix_start], position - prefix_start); + current_arg[position - prefix_start] = '\0'; + + if (strncasecmp(suggestions[suggestion_index], current_arg, strlen(current_arg)) == 0) { + strncpy(suggestion_text, + suggestions[suggestion_index] + strlen(current_arg), + sizeof(suggestion_text) - 1); + } + } else { + if (strncasecmp(suggestions[suggestion_index], buffer, strlen(buffer)) == 0) { + strncpy(suggestion_text, + suggestions[suggestion_index] + strlen(buffer), + sizeof(suggestion_text) - 1); + } + } + + // If there's a non-empty suggestion part and in suggestion mode, accept it + if (strlen(suggestion_text) > 0 && suggestion_active) { + // First Enter press with an active suggestion: Accept it without executing + strncpy(buffer, full_suggestion, bufsize - 1); + buffer[bufsize - 1] = '\0'; + position = strlen(buffer); + + // Redraw line with full accepted suggestion + printf("\r\033[K\033[1;32m➜\033[0m %s", buffer); + fflush(stdout); + + // Switch to execution mode for next Enter press + suggestion_active = 0; + + // Reset suggestion state since we've accepted it + has_suggestion = 0; + if (suggestions) { + for (int i = 0; i < suggestion_count; i++) { + if (suggestions[i]) free(suggestions[i]); + } + free(suggestions); + suggestions = NULL; + suggestion_count = 0; + } + } else { + // No visible suggestion or already accepted: Execute + buffer[position] = '\0'; + printf("\n"); + fflush(stdout); + break; + } + } else { + // No suggestion: Execute the command + buffer[position] = '\0'; + printf("\n"); + fflush(stdout); + break; + } + } else if (c == KEY_BACKSPACE || c == 127) { + // Handle backspace + if (position > 0) { + position--; + buffer[position] = '\0'; + + // Update suggestions after backspace + suggestion_active = 1; // Re-enter suggestion mode + update_suggestions(); + } + } else if (c == KEY_TAB) { + // If we have suggestions, cycle to the next one + suggestion_active = 1; // Ensure we're in suggestion mode + + if (suggestion_count == 1) { + // Only one suggestion - accept it but don't execute + strncpy(buffer, full_suggestion, bufsize - 1); + buffer[bufsize - 1] = '\0'; + position = strlen(buffer); + + // Redraw line with full accepted suggestion + printf("\r\033[K\033[1;32m➜\033[0m %s", buffer); + fflush(stdout); + + // Reset suggestion state to find new suggestions + update_suggestions(); + } else if (suggestion_count > 1) { + // Multiple suggestions - cycle to the next one + suggestion_index = (suggestion_index + 1) % suggestion_count; + display_current_suggestion(); + } + } else if (c == KEY_UP) { + // Navigate history upward + char *history_entry = get_previous_history_entry(&history_position); + if (history_entry) { + // Clear current line + printf("\r\033[K"); + + // Copy history entry to buffer + strncpy(buffer, history_entry, bufsize - 1); + buffer[bufsize - 1] = '\0'; + position = strlen(buffer); + + // Display the history entry and update suggestions + printf("\033[1;32m➜\033[0m %s", buffer); + fflush(stdout); + + // Update suggestions after loading history + suggestion_active = 1; // Re-enter suggestion mode + update_suggestions(); + } + } else if (c == KEY_DOWN) { + // Navigate history downward + char *history_entry = get_next_history_entry(&history_position); + if (history_entry) { + // Clear current line + printf("\r\033[K"); + + // Copy history entry to buffer + strncpy(buffer, history_entry, bufsize - 1); + buffer[bufsize - 1] = '\0'; + position = strlen(buffer); + + // Display the history entry and update suggestions + printf("\033[1;32m➜\033[0m %s", buffer); + fflush(stdout); + + // Update suggestions after loading history + suggestion_active = 1; // Re-enter suggestion mode + update_suggestions(); + } else { + // At the end of history, clear the line + printf("\r\033[K\033[1;32m➜\033[0m "); + buffer[0] = '\0'; + position = 0; + + // Clear suggestions since we have an empty line + if (suggestions) { + for (int i = 0; i < suggestion_count; i++) { + if (suggestions[i]) free(suggestions[i]); + } + free(suggestions); + suggestions = NULL; + suggestion_count = 0; + } + has_suggestion = 0; + suggestion_active = 1; // Re-enter suggestion mode + } + } else if (c == '?') { + // Toggle showing command suggestions + show_suggestions = !show_suggestions; + + // Print the ? character + if (position >= bufsize - 1) { + bufsize += LSH_RL_BUFSIZE; + char *new_buffer = realloc(buffer, bufsize); + if (!new_buffer) { + fprintf(stderr, "lsh: allocation error\n"); + free(buffer); + exit(EXIT_FAILURE); + } + buffer = new_buffer; + } + + buffer[position] = c; + position++; + buffer[position] = '\0'; + printf("%c", c); + + if (show_suggestions) { + // Show command suggestions + printf("\nCommand suggestions:\n"); + + // Check history for similar commands + int suggestions_shown = 0; + char **matching_commands = get_matching_history_entries(buffer); + if (matching_commands) { + for (int i = 0; matching_commands[i] != NULL && suggestions_shown < 5; i++) { + printf(" %s\n", matching_commands[i]); + suggestions_shown++; + } + free_matching_entries(matching_commands); + } + + // Check built-in commands + for (int i = 0; i < lsh_num_builtins() && suggestions_shown < 5; i++) { + if (strncmp(buffer, builtin_str[i], position) == 0) { + printf(" %s\n", builtin_str[i]); + suggestions_shown++; + } + } + + // If we showed suggestions, redisplay the prompt and buffer + if (suggestions_shown > 0) { + printf("\033[1;32m➜\033[0m %s", buffer); + fflush(stdout); + } + + // Update suggestions after ? mode + suggestion_active = 1; // Re-enter suggestion mode + update_suggestions(); + } + } else if (c == KEY_RIGHT && has_suggestion) { + // Right arrow also accepts the current suggestion (without executing) + strncpy(buffer, full_suggestion, bufsize - 1); + buffer[bufsize - 1] = '\0'; + position = strlen(buffer); + + // Redraw line with full accepted suggestion + printf("\r\033[K\033[1;32m➜\033[0m %s", buffer); + fflush(stdout); + + // Reset suggestion state to find new suggestions + suggestion_active = 1; // Re-enter suggestion mode + update_suggestions(); + } else if (isprint(c)) { + // Regular character - add it to the buffer + if (position >= bufsize - 1) { + bufsize += LSH_RL_BUFSIZE; + char *new_buffer = realloc(buffer, bufsize); + if (!new_buffer) { + fprintf(stderr, "lsh: allocation error\n"); + free(buffer); + exit(EXIT_FAILURE); + } + buffer = new_buffer; + } + + buffer[position] = c; + position++; + buffer[position] = '\0'; + + // Update with the new character and show suggestions + suggestion_active = 1; // Re-enter suggestion mode when typing + update_suggestions(); + } + } + + // Clean up suggestions + if (suggestions) { + for (int i = 0; i < suggestion_count; i++) { + if (suggestions[i]) free(suggestions[i]); + } + free(suggestions); + suggestions = NULL; + suggestion_count = 0; + } + has_suggestion = 0; + + return buffer; +} + +/** + * Split a line into tokens + * + * @param line The line to split + * @return NULL-terminated array of tokens + */ +char **lsh_split_line(char *line) { + int bufsize = LSH_TOK_BUFSIZE; + int position = 0; + char **tokens = malloc(bufsize * sizeof(char *)); + char *token; + char *rest = line; + + if (!tokens) { + fprintf(stderr, "lsh: allocation error\n"); + exit(EXIT_FAILURE); + } + + // Handle quotes and ensure we don't split inside quoted strings + while ((token = parse_token(&rest)) != NULL) { + tokens[position] = token; + position++; + + if (position >= bufsize) { + bufsize += LSH_TOK_BUFSIZE; + tokens = realloc(tokens, bufsize * sizeof(char *)); + if (!tokens) { + fprintf(stderr, "lsh: allocation error\n"); + exit(EXIT_FAILURE); + } + } + } + + tokens[position] = NULL; + return tokens; +} + +/** + * Parse a token from a string, handling quoted strings + * + * @param str_ptr Pointer to the string to parse, will be updated + * @return The parsed token, or NULL if no more tokens + */ +char *parse_token(char **str_ptr) { + char *str = *str_ptr; + char *token_start; + + // Skip leading whitespace + while (*str && isspace(*str)) { + str++; + } + + if (*str == '\0') { + *str_ptr = str; + return NULL; // No more tokens + } + + token_start = str; + + if (*str == '"' || *str == '\'') { + // Handle quoted string + char quote = *str; + str++; // Skip the opening quote + token_start = str; // Token starts after the quote + + // Find the closing quote + while (*str && *str != quote) { + str++; + } + + if (*str == quote) { + // Found closing quote + *str = '\0'; // Terminate the token + str++; // Move past the closing quote + } + } else { + // Regular token (not quoted) + while (*str && !isspace(*str)) { + str++; + } + + if (*str) { + *str = '\0'; // Terminate the token + str++; // Move past the terminator + } + } + + *str_ptr = str; + return strdup(token_start); +} + +/** + * Split a line with pipes into separate command arrays + * + * @param line The line to split + * @return NULL-terminated array of NULL-terminated token arrays + */ +char ***lsh_split_piped_line(char *line) { + int cmd_bufsize = LSH_TOK_BUFSIZE; + int cmd_position = 0; + char ***commands = malloc(cmd_bufsize * sizeof(char **)); + char *cmd_str, *save_ptr; + + if (!commands) { + fprintf(stderr, "lsh: allocation error\n"); + exit(EXIT_FAILURE); + } + + // First split by pipe character + cmd_str = strtok_r(line, "|", &save_ptr); + + while (cmd_str != NULL) { + // Allocate space for this command + commands[cmd_position] = lsh_split_line(cmd_str); + cmd_position++; + + // Check if we need more space for commands + if (cmd_position >= cmd_bufsize) { + cmd_bufsize += LSH_TOK_BUFSIZE; + commands = realloc(commands, cmd_bufsize * sizeof(char **)); + if (!commands) { + fprintf(stderr, "lsh: allocation error\n"); + exit(EXIT_FAILURE); + } + } + + cmd_str = strtok_r(NULL, "|", &save_ptr); + } + + commands[cmd_position] = NULL; + return commands; +} diff --git a/line_reader.h b/line_reader.h new file mode 100644 index 0000000..cefe6ba --- /dev/null +++ b/line_reader.h @@ -0,0 +1,57 @@ +/** + * line_reader.h + * Functions for reading and parsing command lines + */ + +#ifndef LINE_READER_H +#define LINE_READER_H + +#include "common.h" + +/** + * Check if a command is valid + * + * @param cmd The command to check + * @return 1 if valid, 0 if not + */ +int is_valid_command(const char *cmd); + +/** + * Read a key from the terminal + * + * Handles special keys and escape sequences + */ +int read_key(void); + +/** + * Read a line of input from the user with tab completion + * + * @return The line read from stdin (must be freed by caller) + */ +char *lsh_read_line(void); + +/** + * Split a line into tokens + * + * @param line The line to split + * @return An array of tokens (must be freed by caller) + */ +char **lsh_split_line(char *line); + +/** + * Parse a token from a string, handling quoted strings + * + * @param str_ptr Pointer to the string to parse, will be updated + * @return The parsed token, or NULL if no more tokens + */ +char *parse_token(char **str_ptr); + +/** + * Split a line with pipes into separate command arrays + * + * @param line The line to split + * @return NULL-terminated array of NULL-terminated token arrays + */ +char ***lsh_split_piped_line(char *line); + +#endif // LINE_READER_H \ No newline at end of file diff --git a/line_reader.o b/line_reader.o new file mode 100644 index 0000000000000000000000000000000000000000..d941ee2dbf5ba2e26f16106cb067121e7edfe22b GIT binary patch literal 42264 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

S~gbn;L?J;ou^&G*c!tJ~B}&;9wq@6Fn| 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 F{V#suXd?gs literal 0 HcmV?d00001 diff --git a/main.c b/main.c new file mode 100644 index 0000000..34879f3 --- /dev/null +++ b/main.c @@ -0,0 +1,26 @@ +/** + * main.c + * Entry point for the LSH shell program + */ + +#include "common.h" +#include "shell.h" +#include + +/** + * Main entry point + */ + +int main(int argc, char **argv) { + // Set locale to support UTF-8 + setlocale(LC_ALL, "en_US.UTF-8"); + + // Setup terminal for proper UTF-8 handling + // This is Linux equivalent of SetConsoleOutputCP(65001) + printf("\033%%G"); // Tell terminal to use UTF-8 + + // Start the shell loop + lsh_loop(); + + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/main.o b/main.o new file mode 100644 index 0000000000000000000000000000000000000000..1f5dd90c1c290d6dc8549918183dc775c15a99a0 GIT binary patch literal 4072 zcmbtWX;4#F6uu!C5P?RpScPg(M06msh(+7lD2j|CRau5wl_VqtYDh2yjn1eDbwQzm z9i}SU#iEW=tyWt1QCvVl+-K@GI#{vQsvV`R)@|rLFX!O%5&yJjCOP-}?)mOH@7()t zvT$rtf}2dn$Yg9Jdx?l;EX?cWSR)KItS1X#X^Ew`5=-tWOXojNEG>MHSl$ID6H6No zDY(Ba0OF4C0Vr_7mjD}&8ZDV=DeAP;gorp6IAFjy27j*Z#wej;nJ=jgCy!DUI>0cGLJ<&{4DJkyV)eyY?D8NK>= zYS(_Y!*1cqYg#X}YK3p$z>LYm`mY>RalPBI=53nd6^jBxPEV`%I6qf@Z0O>~s0T&m zH?m^ufAMb^uD$R?V@vWcs0+HIjvTmXk&MX{KCvBj?h>kgS+`@|^zy^L#gWP}rY%*! zuO9qJRqkaDwl>%TLeA_a_I`#4NY`wQB9N8ux|0 zE?&OT_qV0npRPCm!|r|m##-uEWT(0==(Jj`p2>U_hL+}{w;5Av*u0MCnAs_Qf{Di) zTeLg6oG&XYJM_dcsz?829sw05eUV$Js`{%cS(nHoT@~qL70G+1X3t1S|J4-a8}w-F zw8>k`DwC2lwe0RN_x)7Q<4)_RVV@qSJe4bRln3(LT257)QYPe9hwrb6XgIT5Sz=pb z2#v8;G|Pbpr!VYgw)spjCjp65ag+s@Xdznhw$+4tt{J}2I5cU;-RK5uh>cCqec zOnlmo-WzUKd{)+e&29#K8~-)Y^<@~DcRl>^EkwR z#o0b*=KQHh&KRm?!y}2T0D~j_7Q1=DGqo>()7#Gjith8s4`P4=ekL>J*-xbFhN4Q#9ju zoNK<%Yj~EY%eAPp1jh=DcC$50XEw5YTdu{P&CCTknP#gsA8K%#8+UU4dEV}{zR1I# z!j(&WDDo6f9f}dfLw6`XPQ-hQc+$bz!c~oN)Is1q_-7;XR44GHg{c6XCmu9ly`4_z zFw{ym7zYq9-t{OE4{L-Y{y@UdLYyGs5weLAeg@)H3BLsK#}b}SieAF6L7Xe$Zz3*~ z@b?iflJFxDuafZd5K|uL5A@+0@?WASJ`M3E2_J~~poH&-__BmIBW^_x@3nZp=$@v$ z^gQkm$c^|mC+yf$;Nk3&(K{twpX!2mI9Jgq2t`l)bj0*KM*Jtp$4cVqoQ#n04#eVf z1$m2*AA_FOFGZY;URu8jdFYwAZ%kbGd|_Y#s(;q-;8i$q3SyoH^HGBni()L!dJSoMp|+ zGg^3Ri`8ya^Pi500=q72CSsGNP@QkH<{NGHxwx(|Co|io%QNDG{!gdkdg!4-vW^BZ z-NQ7E$BZC@^9|=p)4@0g4!p!@f8qBIv~*X!h4FB%fQP$QY$akK8cXxTy##CiS3TTw zu;wdgg=5O!osY#P%@6m7z|n(Y@M`p%#bQ2|gt6hAbJf2G*uM-c4EhIqM0)Dqc+R=X zufam84jv{L=?TMo>`H$L^+PBSy;PsUc~|u(Vj$fQP=8ncAwAU(_kyeZp7`8aJ})-X z69@ODtNacOtiwRa55L2tr~LCd2l*puf{(#+Fn_HRc6?J9wudd_Gp_V1JdoB7rE?(F z!~O_*N!&`*(|XN2{-ZqtSQyE zpgxWQ(M$EmIPYrz;^44wqkV$?ga16FC*D$p;Z4b<9F}- literal 0 HcmV?d00001 diff --git a/mingw-get-setup.exe b/mingw-get-setup.exe new file mode 100644 index 0000000000000000000000000000000000000000..0b28bc1c65716b3cd69fcde09f951a9ef29a8fa1 GIT binary patch literal 86528 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

15|NK<-7@^rc)YCPmOqdloHo6by1j;I44j$ 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 z z3Doh`y&SJuce{+MP)Un~u}(9ScRZUgWbmcsj6MvXdAFD<@(7h_Yot|)ed$yKaSt4H zAIto*8Hy<0Vm;+zQzzV{!bS4+{U$hD^GXEBhPpEcGmF4+l^~N{yquj4fjr|hmE+mb z*=^8E9A;B65a=gP(0?Gf)n@qlb+jJ&=NC#!5p_vY3S=f+=|Jlf{?_ZElz;?V7bRXl z8jcnxSF{JO@JB_@`7!hLSr>&k(pNgkV2b>#kLTt1asJR-VHWEZBK8@$$@0+t*X6WC z-mUGDmNj1CDE2IK7)g~i`K>{sq~5%kysO!i>i1I5g_p-YbW|(J8RUZ92WOk~DPtmO zFqAi<8%SV=3VaaI>z>2JQlscIXm22b9?L`X4G1P_Y3-$P1>#4ZBTUw ztn0;>ptO$6Tcbmn)kg{jvW{wq9b%GE1t#cb1&V743K=S`^7X>2RZb7#5|T6a49Fs?iD-&`7Yktr8=ItfB$JBZd%cyVL=e2ac(pfwx#lR556^<#PIr(y zdlT=WH%L2RyqaY9>h1N=3EbRx#&&8>4zP3{_m@FvrT`p7xn(^r_58|2G0vg zB*{WX*Z8YZajAf&;5HUtW5upK7i~1ii$(=h~b6;{B=eod}lHyW#9n|jFkkgwtcj& z_sc90V1)xZe6~{j<|)%VYxRU(z#@t8N|f<^KLIM^b^xOR@E<6_LmycY#D?=4i;hC- z^Jo6iBt#FR%2`a`dt3j0hT6k}&rgCTI3{_L<(F-=?XE~bf~GN0mKr~NSLi}Tu3YM3 z!jFu36#75^p|iGRq{rz4`9-)wn|3FtBg`MxGPk&qWP6}7>I}#!msm2~@JoZv)AScJq zg%fkp$$SiRd#!V3BlYEjqMVUkpb4?55yjlx+yPNs3pil7yTWjD@Vu6UrvxYZ5U|pL zwe&Amz9TH*Y~~l6-9}}rmLMl$GVAXa;-;fDwvvD?!dk_|m*Cn*>y*R0|GOmWjcVm|sbMgs2@^Z)#2@fV5vg^$Ye&YAjr?|;w24E_{(s_f}!NJ37p9 zI3(>$%hs}N&5TbODre=ST9eL?Xte~5OF_6Gd@vT)St-i2XoH@b-nCb%9VPRqBVXU; zY`4v7umEd)7G}~4zpnbqP$iLEvLGg({ccI$b4w)}l5`*5JF8dm^MVBXBHa_HJ871& z>cr3IAfCCMh^R5B;w2tOD(;KtOwWZ2JfbDn~@Pp>i1ln-yyO{!H1Z~lceQUiN zZSWi6B5FjQK~>Brz}WM$tc5T+@uXvDxQFglW4XZ~;fV)Iq0u6OF+Q-#@tqx;^Ttg$ z31;OeH7AezNWgxV_yf77*{GZHy*8QQtS+W~u&rIO!E@nJ3-Y7YU2RK6JPoDpdQ+qQ zvqXLWl2Hpx+MW9z7QSB#f_^w$U@~%LZgYYXm`@2(vqG z>s=$nFMNdQLo)RAILq5CSn0d&Z0qF$`He&}CGRmj6PKCSQe`_1S|%1%%GF z+IQD;BVxbYK^<$evv%7Vc%zz%V8K0LDiykSRRPd< z$O|GJxddsC-0K@t03ni)nki_=G9*BC8iMr1LfZn?W1lvy<3wuorLdNpm=3^$+3i5+ zaO%!6&a_&$sc<|#eh$MyiUOt(^>L;V#n;>ZQT?UX0 z^?@SHH}$;(fi1P~lN#Yp+I}7_B=aSjW(g1Xoqy2peR#+j2^~hJA>d=D{4FqIf-n@L z()*|$lln0L_3`Ev6SxBG;O47(M(J*6;9bg(Bg*R6^_y1;?R&Uq{es)0|*&VS{( zDM0K9nqx3dA2S=}yTDd%|_WRv@n0Z<&0JOhe+VIf9}mT@IW zaG7WLiuU^5%($Yjn`ix@|6h|4|L-BcDt_K(50}QfO3za6BtSmIAhx1~4*Wm;k0<@Y zI-2mt)p8K))3p{cKLdx325mOwRKw4k-pX*&dl~!v zUR#Gl!Fshqs5!|qQ#MRK&I@;Gz^RVN^=aV>?9yiMmn%MqME7;4{u%|%)~9`RQ?t+z zWcbhmL5nDjPp*_88+{;!E>59nBu+Feda{AF#H+IGf^zxsEuvAHi@nz7cjNLC8Hnc&z{Z^$ zigTgnyM8poz)fdPoex451ImROIk6v_!skCQX7O}jjA2wSrqdy6Ge(v}E!}(TCI zEM1-J5hjD6F_!p&#`2&SSkofJ51Lb1Garjf?zAz+lG=EEZ=_0!`Uz=}N)#$c?tUQjy9 zn=$8tZKsq_QNROk;JD!YA3FVTb={Pjo!+523c%Hg>RoSHXbFR?M7anXclP=T8E6Do z-JOl1!TRFqpu}8o#$9?8JzDhrS#7AUmoi|p+J7SXVgr9bG#sLSq*%b`dr3b~k1;E57K|1U(6*QAZ18 zGfX)!)fAFEGZrFM8tAx@2x?3c+^q`~HE#P@!kQ2U2+wf!y{VF>e$^R340BWcUB|^j zWfv5ZXnPKFJ*w$@BZcg07sHVt%2w#pEQ&7xvVNJJy5Bvr!-(LOQBCCc1gbn$MK9r} z@y~AjQ&>~vi`8||quXNUOiNWq2`8bJSsvZNN&h)&dSfH&2(F5;zqXo|Gi*Yh???Bu9ax{NLL0uI9jJjrA5mj10uE6_ zMWSA1g;T&^sOkcr@w~ObI_g}ryE<{aqgbY678l!}oK%vs#%ST=$a~LEXRGJ@6bs>C zxO6~X_Grxt*_g50LCtCUYzjp~&KdC>r0v)mG7jIiw9-WBjn3MZ?)NCx~Vj;G*5IbTi# z;&f=7)kY635qJErpwIZAKr`)A-T$FWtm4@v-fC=*s+Ut%v7Bi%Cu{T)st-F4I?bB);zA05X1GhX287Sj=Kd$ZvL3+0D zU!uJS>?`t>AuHbnmKE4=WTcYMGvS4L0qAI0ENcBS_3wDyG{Bnt(iD2YL*n0vrHrEO z{YO55xIj7OhB-`xnsbHUvF_Z4&nfl`@a7&$w-`$)&KJbTgSRBdarZwJ2)p`;wBrqD92)GX$St2YFNyr{vChpH@9u^ zG$Sn{Gxkk506LV#08G3n+pw|b|_&p_~iGxBjWB+m$DdarZj~VNMZ7~+y>h^ za#FsGr84XqzP1hdcDJus$wMVRT^p+(A>kDaZ-KIkQOG&O+ zf7SKMAeG`h>uhMTbPTQeCi2K7L^9I+Q2P%>EU@sJj)hzV$x1IbkqkoaNu?I38kmzy zyleS!LoL6icPdeYhuI`mRj-u{`l$ujZ?Lb@CnJy%b2=i}CkHSB@lgmH2j(b@*h3lz>I$({z2#C;oLo;8O zjvS45un#tRzzTo7cx3uX>I&sBN;+Xzuu7&d0!^{6{<$6if@m>&YP2qI8?9 zdmeE+>V4?scG?4lFX$hEh5H0T4GZ7K!_b7lvRuqMFZ2AHe)lrxf6#Va?z&fp4GQ7@ zks9S8kggbu5FA+{VR8uKM?cMO6S4$b2ljoDpSRAwR@(0#0!kx}fP3g47Sj5q`(%i$ z-uDNc=D#Cu_b_%Df-FbJIYdK_iSOSwqNFrLxGm*P?B25ot;@RQ z5t4JCUr|;W%Tqp}u5MdmuStcXS&`eaEy0~%pGwfFu@<-&=n*_$t9}t=ss8f<)CI3y zpnoT5Pbi`u-kOUf*t#@%R8R<`8{1K#9P2gckj%Iry(LZ?0P{b|pfK{wVs5R8oy_r< zwY}kS5}p9`rx>D}eD9bMPu?2y1z>Q$SPQ`<`>nHn$%{x$RLjy`p_LX&B<1YY8~N37 zwe0huUdzQhuR;@}F%N&=l6L_$bHGs70EZ1Ci67ocZQ`70ce;z#R`>3}_Da#%g5 z!jPk@N;(NX$K_1v+G2Dq+$~YZKMe#i{gSnjGwVZ<&Q>yS+PQYhR7}5{SDa6Yku^PR z6u1n+r<-rqcOvXWR;IPvDFpS6#jDyehbg;+;yeY2jttaWgC#wDfuM-7dz{G*0f_t= zOrpD(8h1GdCOz-?I!p)Y<_{UttFB8w4Mn1?QWNWh-7MA5E|ehZUmdEGL%B0G%{3?{ z`=+R#y1@|EU7m>l(g!35gc$|%$*;q`l~$Zq>pvQp79EnBuAP5$%{|wA)Gw(xG{gqs zAcrufywx=w7ZmZd+p1y2t^u8^7NCtX^TvX*3c043;*FF_s-Fx6oM;T7Ebl%@_W-I7 z+q^FI2pkZ(A~XhRlm7WyR`__TNDGw+!NrTsrKnu16El2BNtteKKgGu4TF%?QHS72= zfd59YP&r~?zassy{W-g(LOLQTom(PUfNLx(0C@$(PlLNC1%uT2U;4lceH?-zj#wo$ z;;CY`0SYTxDV`J#RogL$6jt_}@m3Xs%XgQXSNKtZ1f#VoxTEq9_x+A^Ro;jhOCe$b z{r|d4qtv0k3_1u&SfQ@v{*(c}0ZIBm(3iUb&F3$^>%`4V=_d7-& zm(A=kk1EHo!T4&!5sA+4((~b7z&}N_(CiU04SuQWepf`lbT8JmMO%Dv<6_GnZ%RWU zMF*{}YDY`>Bsilm7d$$xG4zRh0;iXENc>BOW5W*!rb=MnapzVWuX!3nG$puH%4)(= zB-P`yPF?{;L~T`MH$xTT8lW*aVuKxb9k^iX|qW_q2F!3 zG)*TrN2l1JHM7PeK@h#aTiJvt!bd@XD8!t-N^;q= z14o0azYi5M&C*F04k@;lru`P{8omz&rV8~E&=&-NO5{ZVI3)VsNquz@LQ)z+

  • = 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 literal 0 HcmV?d00001 diff --git a/persistent_history.c b/persistent_history.c new file mode 100644 index 0000000..fda5608 --- /dev/null +++ b/persistent_history.c @@ -0,0 +1,502 @@ +/** + * persistent_history.c + * Implementation of persistent command history and frequency tracking + */ + +#include "persistent_history.h" +#include +#include +#include +#include +#include +#include +#include +#include + +// Global variables for persistent history +static PersistentHistoryEntry *history_entries = NULL; +static int history_size = 0; +static int history_capacity = 0; +static int history_position = 0; + +// Global variables for frequency tracking +static CommandFrequency *command_frequencies = NULL; +static int frequency_count = 0; +static int frequency_capacity = 0; + +// Paths for history and frequency files +static char history_file_path[PATH_MAX]; +static char frequency_file_path[PATH_MAX]; + +/** + * Initialize the persistent history system + */ +void init_persistent_history(void) { + // Allocate initial history capacity + history_capacity = PERSISTENT_HISTORY_SIZE; + history_entries = (PersistentHistoryEntry *)malloc(history_capacity * sizeof(PersistentHistoryEntry)); + if (!history_entries) { + fprintf(stderr, "Failed to allocate memory for history entries\n"); + return; + } + + // Allocate initial frequency capacity + frequency_capacity = 100; + command_frequencies = (CommandFrequency *)malloc(frequency_capacity * sizeof(CommandFrequency)); + if (!command_frequencies) { + fprintf(stderr, "Failed to allocate memory for command frequencies\n"); + free(history_entries); + history_entries = NULL; + return; + } + + // Initialize history and frequency counters + history_size = 0; + history_position = -1; + frequency_count = 0; + + // Set up file paths + char *home_dir = getenv("HOME"); + if (home_dir) { + // Create .lsh directory if it doesn't exist + char lsh_dir[PATH_MAX]; + snprintf(lsh_dir, sizeof(lsh_dir), "%s/.lsh", home_dir); + + struct stat st = {0}; + if (stat(lsh_dir, &st) == -1) { + mkdir(lsh_dir, 0700); + } + + snprintf(history_file_path, sizeof(history_file_path), "%s/.lsh/history", home_dir); + snprintf(frequency_file_path, sizeof(frequency_file_path), "%s/.lsh/frequency", home_dir); + } else { + // Fallback to current directory + strcpy(history_file_path, ".lsh_history"); + strcpy(frequency_file_path, ".lsh_frequency"); + } + + // Load history and frequency data + load_history_from_file(); + load_frequencies_from_file(); +} + +/** + * Clean up persistent history resources + */ +void cleanup_persistent_history(void) { + if (history_entries) { + for (int i = 0; i < history_size; i++) { + free(history_entries[i].command); + } + free(history_entries); + history_entries = NULL; + } + + if (command_frequencies) { + for (int i = 0; i < frequency_count; i++) { + free(command_frequencies[i].command); + } + free(command_frequencies); + command_frequencies = NULL; + } + + history_size = 0; + history_capacity = 0; + frequency_count = 0; + frequency_capacity = 0; +} + +/** + * Shutdown persistent history + */ +void shutdown_persistent_history(void) { + save_history_to_file(); + save_frequencies_to_file(); + cleanup_persistent_history(); +} + +/** + * Add a command to the persistent history + */ +void add_to_history(const char *command) { + if (!command || !*command || !history_entries) { + return; // Skip empty commands + } + + // Check for duplicates (don't add the same command twice in a row) + if (history_size > 0 && strcmp(history_entries[history_size - 1].command, command) == 0) { + return; + } + + // Update command frequency + update_command_frequency(command); + + // Add to history + if (history_size >= history_capacity) { + // History is full, shift entries + free(history_entries[0].command); + memmove(&history_entries[0], &history_entries[1], + (history_capacity - 1) * sizeof(PersistentHistoryEntry)); + history_size = history_capacity - 1; + } + + // Add new entry + history_entries[history_size].command = strdup(command); + history_entries[history_size].timestamp = time(NULL); + history_size++; + + // Reset history position for navigation + history_position = -1; +} + +/** + * Update command frequency statistics + */ +void update_command_frequency(const char *command) { + if (!command || !*command || !command_frequencies) { + return; + } + + // Check if command exists in frequencies + for (int i = 0; i < frequency_count; i++) { + if (strcmp(command_frequencies[i].command, command) == 0) { + // Update existing entry + command_frequencies[i].count++; + return; + } + } + + // Add new frequency entry + if (frequency_count >= frequency_capacity) { + // Expand capacity + frequency_capacity *= 2; + CommandFrequency *new_freq = (CommandFrequency *)realloc( + command_frequencies, frequency_capacity * sizeof(CommandFrequency)); + if (!new_freq) { + fprintf(stderr, "Failed to allocate memory for command frequencies\n"); + return; + } + command_frequencies = new_freq; + } + + // Add new entry + command_frequencies[frequency_count].command = strdup(command); + command_frequencies[frequency_count].count = 1; + frequency_count++; +} + +/** + * Save history to file + */ +void save_history_to_file(void) { + if (!history_entries || history_size == 0) { + return; + } + + FILE *fp = fopen(history_file_path, "w"); + if (!fp) { + fprintf(stderr, "Failed to open history file for writing: %s\n", history_file_path); + return; + } + + // Write version and metadata + fprintf(fp, "# LSH Persistent History\n"); + fprintf(fp, "# Version: 1.0\n"); + fprintf(fp, "# Format: timestamp command\n\n"); + + // Write entries + for (int i = 0; i < history_size; i++) { + fprintf(fp, "%ld %s\n", (long)history_entries[i].timestamp, history_entries[i].command); + } + + fclose(fp); +} + +/** + * Load history from file + */ +void load_history_from_file(void) { + FILE *fp = fopen(history_file_path, "r"); + if (!fp) { + return; // File doesn't exist or can't be opened + } + + char line[1024]; + time_t timestamp; + char command[900]; // Allow space for timestamp and whitespace + + // Skip header lines + while (fgets(line, sizeof(line), fp) && line[0] == '#') { + // Skip header line + } + + // Clear history + for (int i = 0; i < history_size; i++) { + free(history_entries[i].command); + } + history_size = 0; + + // Read entries + while (fgets(line, sizeof(line), fp)) { + // Parse line: timestamp command + if (sscanf(line, "%ld %[^\n]", ×tamp, command) == 2) { + if (history_size < history_capacity) { + history_entries[history_size].command = strdup(command); + history_entries[history_size].timestamp = timestamp; + history_size++; + } + } + } + + fclose(fp); +} + +/** + * Save command frequencies to file + */ +void save_frequencies_to_file(void) { + if (!command_frequencies || frequency_count == 0) { + return; + } + + FILE *fp = fopen(frequency_file_path, "w"); + if (!fp) { + fprintf(stderr, "Failed to open frequency file for writing: %s\n", frequency_file_path); + return; + } + + // Write version and metadata + fprintf(fp, "# LSH Command Frequencies\n"); + fprintf(fp, "# Version: 1.0\n"); + fprintf(fp, "# Format: count command\n\n"); + + // Write entries + for (int i = 0; i < frequency_count; i++) { + fprintf(fp, "%d %s\n", command_frequencies[i].count, command_frequencies[i].command); + } + + fclose(fp); +} + +/** + * Load command frequencies from file + */ +void load_frequencies_from_file(void) { + FILE *fp = fopen(frequency_file_path, "r"); + if (!fp) { + return; // File doesn't exist or can't be opened + } + + char line[1024]; + int count; + char command[900]; // Allow space for count and whitespace + + // Skip header lines + while (fgets(line, sizeof(line), fp) && line[0] == '#') { + // Skip header line + } + + // Clear frequencies + for (int i = 0; i < frequency_count; i++) { + free(command_frequencies[i].command); + } + frequency_count = 0; + + // Read entries + while (fgets(line, sizeof(line), fp)) { + // Parse line: count command + if (sscanf(line, "%d %[^\n]", &count, command) == 2) { + if (frequency_count < frequency_capacity) { + command_frequencies[frequency_count].command = strdup(command); + command_frequencies[frequency_count].count = count; + frequency_count++; + } + } + } + + fclose(fp); +} + +/** + * Get the history entry at the specified index + */ +PersistentHistoryEntry *get_history_entry(int index) { + if (index < 0 || index >= history_size) { + return NULL; + } + return &history_entries[index]; +} + +/** + * Get the total number of history entries + */ +int get_history_count(void) { + return history_size; +} + +/** + * Find the best matching command based on frequency + */ +char *find_best_frequency_match(const char *prefix) { + if (!prefix || !*prefix || !command_frequencies) { + return NULL; + } + + int best_freq = 0; + int best_index = -1; + + // Find the most frequent command that starts with the prefix + for (int i = 0; i < frequency_count; i++) { + if (strncasecmp(command_frequencies[i].command, prefix, strlen(prefix)) == 0) { + if (command_frequencies[i].count > best_freq) { + best_freq = command_frequencies[i].count; + best_index = i; + } + } + } + + if (best_index >= 0) { + return strdup(command_frequencies[best_index].command); + } + + return NULL; +} + +/** + * Debug function to print frequency data + */ +void debug_print_frequencies(void) { + printf("Command Frequencies:\n"); + for (int i = 0; i < frequency_count; i++) { + printf("%3d: %s (%d)\n", i + 1, command_frequencies[i].command, command_frequencies[i].count); + } +} + +/** + * Case-insensitive substring search + */ +char *_stristr(const char *haystack, const char *needle) { + if (!haystack || !needle) + return NULL; + + char *h = strdup(haystack); + char *n = strdup(needle); + + if (!h || !n) { + if (h) free(h); + if (n) free(n); + return NULL; + } + + // Convert both strings to lowercase + for (char *p = h; *p; p++) + *p = tolower(*p); + for (char *p = n; *p; p++) + *p = tolower(*p); + + char *result = strstr(h, n); + char *original = NULL; + + // If found, map back to original string position + if (result) { + original = (char *)haystack + (result - h); + } + + free(h); + free(n); + return original; +} + +/** + * Get previous history entry for up-arrow key navigation + */ +char *get_previous_history_entry(int *position) { + if (!history_entries || history_size == 0) { + return NULL; + } + + if (*position < 0) { + // First time accessing history, start from the most recent entry + *position = history_size - 1; + } else if (*position > 0) { + // Move to previous entry + (*position)--; + } else { + // Already at the oldest entry, can't go back further + return history_entries[0].command; + } + + return history_entries[*position].command; +} + +/** + * Get next history entry for down-arrow key navigation + */ +char *get_next_history_entry(int *position) { + if (!history_entries || history_size == 0 || *position < 0) { + return NULL; + } + + if (*position < history_size - 1) { + // Move to next (more recent) entry + (*position)++; + return history_entries[*position].command; + } else { + // We've reached the end of history, return NULL to indicate + // user should get an empty prompt + *position = -1; + return NULL; + } +} + +/** + * Get matching history entries for tab completion + */ +char **get_matching_history_entries(const char *prefix) { + if (!prefix || !history_entries) { + return NULL; + } + + // Count matching entries + int matches = 0; + for (int i = 0; i < history_size; i++) { + if (strncasecmp(history_entries[i].command, prefix, strlen(prefix)) == 0) { + matches++; + } + } + + if (matches == 0) { + return NULL; + } + + // Allocate result array + char **result = (char **)malloc((matches + 1) * sizeof(char *)); + if (!result) { + return NULL; + } + + // Fill the array with matching commands + int count = 0; + for (int i = 0; i < history_size && count < matches; i++) { + if (strncasecmp(history_entries[i].command, prefix, strlen(prefix)) == 0) { + result[count++] = strdup(history_entries[i].command); + } + } + result[count] = NULL; + + return result; +} + +/** + * Free matching entries array + */ +void free_matching_entries(char **entries) { + if (!entries) { + return; + } + + for (int i = 0; entries[i] != NULL; i++) { + free(entries[i]); + } + free(entries); +} \ No newline at end of file diff --git a/persistent_history.h b/persistent_history.h new file mode 100644 index 0000000..1043095 --- /dev/null +++ b/persistent_history.h @@ -0,0 +1,85 @@ +/** + * persistent_history.h + * Functions for persistent command history and frequency tracking + */ + +#ifndef PERSISTENT_HISTORY_H +#define PERSISTENT_HISTORY_H + +#include "common.h" +#include "shell.h" +#include + +// Increase history size for persistent storage +#define PERSISTENT_HISTORY_SIZE 1000 + +// Structure for a history entry +typedef struct { + char *command; + time_t timestamp; +} PersistentHistoryEntry; + +// Structure for command frequency tracking +typedef struct { + char *command; + int count; +} CommandFrequency; + +// Initialize persistent history +void init_persistent_history(void); + +// Clean up persistent history +void cleanup_persistent_history(void); + +// Shutdown persistent history +void shutdown_persistent_history(void); + +// Add a command to persistent history +void add_to_history(const char *command); + +// Get command suggestions based on prefix and frequency +char **get_frequency_suggestions(const char *prefix, int *num_suggestions); + +// Save history to file +void save_history_to_file(void); + +// Load history from file +void load_history_from_file(void); + +// Update command frequency +void update_command_frequency(const char *command); + +// Save frequencies to file +void save_frequencies_to_file(void); + +// Load frequencies from file +void load_frequencies_from_file(void); + +// Get the history entry at specified index +PersistentHistoryEntry *get_history_entry(int index); + +// Get the total number of history entries +int get_history_count(void); + +// Find the best matching command based on frequency +char *find_best_frequency_match(const char *prefix); + +// Debug print frequency data +void debug_print_frequencies(void); + +// String search (case insensitive) +char *_stristr(const char *haystack, const char *needle); + +// Get previous history entry +char *get_previous_history_entry(int *position); + +// Get next history entry +char *get_next_history_entry(int *position); + +// Get matching history entries +char **get_matching_history_entries(const char *prefix); + +// Free matching entries +void free_matching_entries(char **entries); + +#endif // PERSISTENT_HISTORY_H \ No newline at end of file diff --git a/persistent_history.o b/persistent_history.o new file mode 100644 index 0000000000000000000000000000000000000000..ed2c3926c46744eca1f8fa6cb1ce646ac8c0bf0b GIT binary patch literal 25880 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 IKXm>70pc%$8UO$Q literal 0 HcmV?d00001 diff --git a/ps_command.c b/ps_command.c new file mode 100644 index 0000000..bb37ef5 --- /dev/null +++ b/ps_command.c @@ -0,0 +1,113 @@ +/** + * ps_command.c + * Implementation of the 'ps' command for listing running processes + * Simple implementation for Linux + */ + +#include "builtins.h" +#include "common.h" +#include "structured_data.h" +#include +#include +#include + +/** + * Function to generate structured data for running processes + * This enables piping and filtering of process information + * + * @param args Command arguments + * @return TableData structure with process information + */ +TableData* lsh_ps_structured(char **args) { + // Define our table headers + char *headers[] = {"PID", "Name", "Memory", "Threads"}; + int header_count = 4; + + // Create our table + TableData *table = create_table(headers, header_count); + if (!table) { + fprintf(stderr, "lsh: allocation error in ps_structured\n"); + return NULL; + } + + // Use system's ps command to get process info + FILE *fp = popen("ps -e -o pid,comm,vsz,nlwp --no-headers", "r"); + if (!fp) { + fprintf(stderr, "lsh: failed to execute ps command\n"); + free_table(table); + return NULL; + } + + char line[1024]; + while (fgets(line, sizeof(line), fp)) { + // Parse the line + char name[256] = {0}; + unsigned long pid = 0, vsz = 0, threads = 0; + + sscanf(line, "%lu %255s %lu %lu", &pid, name, &vsz, &threads); + + // Create a new row for this process + DataValue *row = (DataValue*)malloc(header_count * sizeof(DataValue)); + if (!row) { + fprintf(stderr, "lsh: allocation error in ps_structured\n"); + free_table(table); + pclose(fp); + return NULL; + } + + // Set PID (as a string for compatibility) + char pidStr[20]; + sprintf(pidStr, "%lu", pid); + row[0].type = TYPE_STRING; + row[0].value.str_val = strdup(pidStr); + + // Set process name + row[1].type = TYPE_STRING; + row[1].value.str_val = strdup(name); + + // Format memory usage string (important for filtering) + char memoryString[32]; + if (vsz < 1024) { + sprintf(memoryString, "%lu B", vsz); + } else if (vsz < 1024 * 1024) { + sprintf(memoryString, "%.1f KB", vsz / 1024.0); + } else { + // Format as MB for consistency in filtering + sprintf(memoryString, "%.1f MB", vsz / (1024.0 * 1024.0)); + } + + row[2].type = TYPE_SIZE; // Use the special SIZE type for filtering + row[2].value.str_val = strdup(memoryString); + + // Set thread count + char threadStr[20]; + sprintf(threadStr, "%lu", threads); + row[3].type = TYPE_STRING; + row[3].value.str_val = strdup(threadStr); + + // Add the row to the table + add_table_row(table, row); + } + + pclose(fp); + return table; +} + +/** + * Implementation of the ps command to display process information + * Uses structured data to show processes in a formatted table + */ +int lsh_ps_fancy(char **args) { + // Create structured data table for processes + TableData *table = lsh_ps_structured(args); + + if (table) { + // Print the table using our nice formatting + print_table(table); + + // Free the table + free_table(table); + } + + return 1; +} \ No newline at end of file diff --git a/ps_command.o b/ps_command.o new file mode 100644 index 0000000000000000000000000000000000000000..0b68cead7000f57a0e0f13f893ef2fd3e6e77ddc GIT binary patch literal 10784 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 K)RmS<|NjAtiwLOz literal 0 HcmV?d00001 diff --git a/rg_selection.txt b/rg_selection.txt new file mode 100644 index 0000000..e69de29 diff --git a/ripgrep.c b/ripgrep.c new file mode 100644 index 0000000..8967d5a --- /dev/null +++ b/ripgrep.c @@ -0,0 +1,746 @@ +/** + * ripgrep.c + * Interactive wrapper for the ripgrep (rg) command-line search tool + */ + +#include "ripgrep.h" +#include "common.h" +#include "line_reader.h" +#include "shell.h" // Add this for lsh_execute +#include +#include +#include +#include +#include // For PATH_MAX +#include // For access function +#include // For terminal control + +/** + * Check if ripgrep (rg) is installed on the system + * + * @return 1 if installed, 0 if not + */ +int is_rg_installed(void) { + // Try to run rg --version to check if it's installed + FILE *fp = popen("rg --version 2>/dev/null", "r"); + if (fp == NULL) { + return 0; + } + + // Read output (if any) + char buffer[128]; + int has_output = (fgets(buffer, sizeof(buffer), fp) != NULL); + + // Close the process + pclose(fp); + + return has_output; +} + +/** + * Display instructions for installing ripgrep + */ +void show_rg_install_instructions(void) { + printf("\nripgrep (rg) is not installed on this system. To use this feature, " + "install ripgrep:\n\n"); + printf("Installation options:\n"); + printf("1. Using package manager (Debian/Ubuntu):\n"); + printf(" sudo apt install ripgrep\n\n"); + printf("2. Using package manager (Fedora):\n"); + printf(" sudo dnf install ripgrep\n\n"); + printf("3. Using package manager (Arch Linux):\n"); + printf(" sudo pacman -S ripgrep\n\n"); + printf("4. Download prebuilt binary from: " + "https://github.com/BurntSushi/ripgrep/releases\n\n"); + printf("After installation, restart your shell.\n"); +} + +/** + * Check if a specific editor is available + * + * @param editor Name of the editor executable + * @return 1 if available, 0 if not + */ +int is_editor_available_for_rg(const char *editor) { + char command[256]; + snprintf(command, sizeof(command), "%s --version >/dev/null 2>&1", editor); + return (system(command) == 0); +} + +/** + * Open a file at a specific line in the best available editor + * + * @param file_path Path to the file to open + * @param line_number Line number to position cursor at + * @return 1 if successful, 0 if failed + */ +int rg_open_in_editor(const char *file_path, int line_number) { + char command[2048] = {0}; + int success = 0; + + // Try to detect available editors (in order of preference) + if (is_editor_available_for_rg("nvim")) { + // Neovim is available - construct command with +line_number + snprintf(command, sizeof(command), "nvim +%d \"%s\"", line_number, + file_path); + success = 1; + } else if (is_editor_available_for_rg("vim")) { + // Vim is available + snprintf(command, sizeof(command), "vim +%d \"%s\"", line_number, + file_path); + success = 1; + } else if (is_editor_available_for_rg("nano")) { + // Try nano if available + // Note: nano doesn't have perfect line number navigation + snprintf(command, sizeof(command), "nano +%d \"%s\"", line_number, + file_path); + success = 1; + } else if (is_editor_available_for_rg("code")) { + // VSCode with line number + snprintf(command, sizeof(command), "code -g \"%s:%d\" -r", file_path, + line_number); + success = 1; + } else if (is_editor_available_for_rg("gedit")) { + // gedit as last resort (limited line number support) + snprintf(command, sizeof(command), "gedit +%d \"%s\"", line_number, file_path); + success = 1; + } + + if (success) { + // Clear the screen before launching the editor + system("clear"); + + // Execute the command directly in the current terminal + int result = system(command); + success = (result == 0); + + return success; + } else { + // No suitable editor found + printf("No compatible editor (neovim, vim, nano, VSCode, gedit) found.\n"); + return 0; + } +} + +/** + * Parse a ripgrep result line to extract file path and line number + * + * @param result_line The result line from ripgrep (format: + * file:line:column:text) + * @param file_path Buffer to store extracted file path + * @param file_path_size Size of file_path buffer + * @param line_number Pointer to store extracted line number + * @return 1 if parsing successful, 0 if failed + */ +static int parse_rg_result(const char *result_line, char *file_path, + size_t file_path_size, int *line_number) { + // Ripgrep output format is: file:line:column:text + const char *first_colon = strchr(result_line, ':'); + if (!first_colon) + return 0; + + const char *second_colon = strchr(first_colon + 1, ':'); + if (!second_colon) + return 0; + + // Extract file path + size_t path_length = first_colon - result_line; + if (path_length >= file_path_size) + path_length = file_path_size - 1; + strncpy(file_path, result_line, path_length); + file_path[path_length] = '\0'; + + // Extract line number + char line_str[16] = {0}; + size_t line_str_length = second_colon - (first_colon + 1); + if (line_str_length >= sizeof(line_str)) + line_str_length = sizeof(line_str) - 1; + strncpy(line_str, first_colon + 1, line_str_length); + line_str[line_str_length] = '\0'; + + *line_number = atoi(line_str); + return 1; +} + +/** + * Run ripgrep with interactive filtering + * + * @param args Command arguments or NULL for interactive mode + * @return Selected filename/line or NULL if canceled + */ +char *run_interactive_ripgrep(char **args) { + // Check if ripgrep is installed + if (!is_rg_installed()) { + show_rg_install_instructions(); + return NULL; + } + + // Create temporary files for the search results + char temp_rg_results[PATH_MAX] = "/tmp/rg_results.txt"; + char temp_fzf_output[PATH_MAX] = "/tmp/rg_selected.txt"; + + // Build the initial command + char command[4096] = {0}; + + // Base ripgrep command with sensible defaults + strcpy(command, + "rg --line-number --column --no-heading --color=always --smart-case"); + + // Add any user-provided arguments + if (args && args[1] != NULL) { + int i = 1; + while (args[i] != NULL) { + strcat(command, " "); + + // If the argument contains spaces, quote it + if (strchr(args[i], ' ') != NULL) { + strcat(command, "\""); + strcat(command, args[i]); + strcat(command, "\""); + } else { + strcat(command, args[i]); + } + i++; + } + } else { + // If no search pattern provided, use empty string to search all files + // Will be filtered by fzf as user types + strcat(command, " \"\""); + } + + // Pipe to fzf for interactive selection with preview + strcat(command, " | fzf --ansi"); + + // Add keybindings for navigation + strcat(command, " --bind=\"ctrl-j:down,ctrl-k:up,/:toggle-search\""); + + // Add preview window showing file content with line highlighted + strcat(command, " --preview=\"bat --color=always --style=numbers " + "--highlight-line={2} {1}\""); + strcat(command, " --preview-window=+{2}-10"); + + // Add output redirection + strcat(command, " > "); + strcat(command, temp_fzf_output); + + // Run the command + printf("Starting interactive ripgrep search...\n"); + int result = system(command); + + // Check if user canceled (fzf returns non-zero) + if (result != 0) { + unlink(temp_fzf_output); + return NULL; + } + + // Read the selected result from the temporary file + FILE *fp = fopen(temp_fzf_output, "r"); + if (!fp) { + unlink(temp_fzf_output); + return NULL; + } + + // Read the selected line + char *selected = (char *)malloc(PATH_MAX * 2); + if (!selected) { + fclose(fp); + unlink(temp_fzf_output); + return NULL; + } + + if (fgets(selected, PATH_MAX * 2, fp) == NULL) { + fclose(fp); + unlink(temp_fzf_output); + free(selected); + return NULL; + } + + // Remove newline if present + size_t len = strlen(selected); + if (len > 0 && selected[len - 1] == '\n') { + selected[len - 1] = '\0'; + } + + // Close and delete the temporary file + fclose(fp); + unlink(temp_fzf_output); + + return selected; +} + +/** + * Run ripgrep with interactive editing capabilities for a custom Neovim-like + * experience + */ +void run_ripgrep_interactive_session(void) { + // Check if ripgrep and fzf are installed + if (!is_rg_installed()) { + show_rg_install_instructions(); + return; + } + + // Initialize the search query + char search_query[256] = ""; + char last_query[256] = ""; + + // Create a temporary file for results + char temp_results[PATH_MAX] = "/tmp/ripgrep_results.txt"; + + // Save original terminal settings to restore later + struct termios old_tio, new_tio; + tcgetattr(STDIN_FILENO, &old_tio); + + // Copy the old settings and modify for raw input + new_tio = old_tio; + new_tio.c_lflag &= ~(ICANON | ECHO); // Disable canonical mode and echo + new_tio.c_cc[VMIN] = 1; // Read one character at a time + new_tio.c_cc[VTIME] = 0; // No timeout + tcsetattr(STDIN_FILENO, TCSANOW, &new_tio); + + // Clear screen and show initial UI + system("clear"); + printf("--- Interactive Ripgrep Search ---\n"); + printf( + "Type to search | Ctrl+N/P: navigate | Enter: open | Ctrl+C: exit\n\n"); + printf("Search: "); + + int running = 1; + int selected_index = 0; + int results_count = 0; + char **results = NULL; + + // Main interaction loop + while (running) { + // Display the current search query + printf("\rSearch: %s", search_query); + fflush(stdout); + + // Check if the query has changed and we need to run ripgrep again + if (strcmp(search_query, last_query) != 0) { + // Free previous results if any + if (results) { + for (int i = 0; i < results_count; i++) { + free(results[i]); + } + free(results); + results = NULL; + results_count = 0; + } + + // Execute ripgrep with the current query if not empty + if (strlen(search_query) > 0) { + // Build ripgrep command + char command[4096]; + snprintf(command, sizeof(command), + "rg --line-number --column --no-heading --color=never " + "--smart-case \"%s\" > %s", + search_query, temp_results); + + system(command); + + // Read results from the temp file + FILE *fp = fopen(temp_results, "r"); + if (fp) { + // Count lines first + char line[1024]; + results_count = 0; + + while (fgets(line, sizeof(line), fp) != NULL) { + results_count++; + } + + // Allocate memory for results + rewind(fp); + results = (char **)malloc(results_count * sizeof(char *)); + + if (results) { + int i = 0; + while (i < results_count && fgets(line, sizeof(line), fp) != NULL) { + // Remove newline + size_t len = strlen(line); + if (len > 0 && line[len - 1] == '\n') { + line[len - 1] = '\0'; + } + + results[i] = strdup(line); + i++; + } + } + + fclose(fp); + } + } + + // Update last query + strcpy(last_query, search_query); + + // Reset selection to first result + selected_index = 0; + + // Clear the results display area + printf("\n\033[J"); // Clear from cursor to end of screen + + // Display results count + printf("\nFound %d matches\n\n", results_count); + + // Display results with selection + int max_display = 10; // Show at most 10 results at a time + for (int i = 0; i < results_count && i < max_display; i++) { + if (i == selected_index) { + printf("\033[7m> %s\033[0m\n", + results[i]); // Invert colors for selection + } else { + printf(" %s\n", results[i]); + } + } + } + + // Process user input + unsigned char c; + if (read(STDIN_FILENO, &c, 1) > 0) { + if (c == 3) { // Ctrl+C + running = 0; + } else if (c == 13 || c == 10) { // Enter or newline + // Open the selected file if there are results + if (results_count > 0 && selected_index < results_count) { + char file_path[PATH_MAX]; + int line_number; + + if (parse_rg_result(results[selected_index], file_path, + sizeof(file_path), &line_number)) { + rg_open_in_editor(file_path, line_number); + + // After returning from editor, refresh the UI + system("clear"); + printf("--- Interactive Ripgrep Search ---\n"); + printf("Type to search | Ctrl+N/P: navigate | Enter: open | Ctrl+C: " + "exit\n\n"); + printf("Search: %s\n\n", search_query); + + // Re-display results count + printf("Found %d matches\n\n", results_count); + + // Re-display results with selection + int max_display = 10; + for (int i = 0; i < results_count && i < max_display; i++) { + if (i == selected_index) { + printf("\033[7m> %s\033[0m\n", results[i]); + } else { + printf(" %s\n", results[i]); + } + } + } + } + } else if (c == 14) { // Ctrl+N + if (results_count > 0) { + selected_index = (selected_index + 1) % results_count; + + // Redraw results with new selection + printf("\033[%dA", + results_count > 10 + ? 10 + : results_count); // Move cursor up to results start + + int max_display = 10; + for (int i = 0; i < results_count && i < max_display; i++) { + if (i == selected_index) { + printf("\033[2K\033[7m> %s\033[0m\n", + results[i]); // Clear line and invert colors + } else { + printf("\033[2K %s\n", results[i]); // Clear line + } + } + } + } else if (c == 16) { // Ctrl+P + if (results_count > 0) { + selected_index = (selected_index - 1 + results_count) % results_count; + + // Redraw results with new selection + printf("\033[%dA", + results_count > 10 + ? 10 + : results_count); // Move cursor up to results start + + int max_display = 10; + for (int i = 0; i < results_count && i < max_display; i++) { + if (i == selected_index) { + printf("\033[2K\033[7m> %s\033[0m\n", + results[i]); // Clear line and invert colors + } else { + printf("\033[2K %s\n", results[i]); // Clear line + } + } + } + } else if (c == 127 || c == 8) { // Backspace (127 on Linux, 8 on some terminals) + // Remove last character from search query + size_t len = strlen(search_query); + if (len > 0) { + search_query[len - 1] = '\0'; + } + } else if (isprint(c)) { // Printable character + // Add character to search query + size_t len = strlen(search_query); + if (len < sizeof(search_query) - 1) { + search_query[len] = c; + search_query[len + 1] = '\0'; + } + } + } + } + + // Clean up + if (results) { + for (int i = 0; i < results_count; i++) { + free(results[i]); + } + free(results); + } + + unlink(temp_results); + + // Restore original terminal settings + tcsetattr(STDIN_FILENO, TCSANOW, &old_tio); + + // Final screen clear + system("clear"); +} + +/** + * Command handler for the ripgrep command + * + * @param args Command arguments + * @return 1 to continue shell execution, 0 to exit shell + */ +int lsh_ripgrep(char **args) { + // Check if ripgrep is installed + if (!is_rg_installed()) { + printf("Ripgrep (rg) is not installed. Falling back to custom " + "implementation.\n"); + printf("For better performance, consider installing ripgrep:\n"); + show_rg_install_instructions(); + printf("\nRunning with custom implementation...\n\n"); + + // Fall back to our custom implementation + run_ripgrep_interactive_session(); + return 1; + } + + // Also check if fzf is installed for the interactive UI + int fzf_available = is_fzf_installed(); // Reuse from fzf_native.h + + // Check for help flag + if (args[1] && + (strcmp(args[1], "--help") == 0 || strcmp(args[1], "-h") == 0)) { + printf("Usage: ripgrep [pattern] [options]\n"); + printf("Interactive code search using ripgrep (rg) with fzf.\n\n"); + printf("If called without arguments, launches fzf with ripgrep for " + "interactive searching.\n\n"); + printf("Options:\n"); + printf(" -t, --type [TYPE] Only search files matching TYPE (e.g., -t " + "cpp)\n"); + printf(" -i, --ignore-case Case insensitive search\n"); + printf(" -w, --word-regexp Only match whole words\n"); + printf(" -e, --regexp Treat pattern as a regular expression\n"); + printf(" -f, --fixed-strings Treat pattern as a literal string\n"); + printf(" -g, --glob [GLOB] Include/exclude files matching the glob\n"); + return 1; + } + + // If no arguments provided, use fzf with ripgrep + if (!args[1]) { + if (!fzf_available) { + printf("fzf is not installed. Falling back to custom implementation.\n"); + show_fzf_install_instructions(); + printf("\nRunning with custom implementation...\n\n"); + + // Fall back to custom implementation if fzf is not available + run_ripgrep_interactive_session(); + return 1; + } + + // Create a temporary file for the fzf preview script + char preview_script[PATH_MAX] = "/tmp/fzf_preview.sh"; + + // Create the preview script as a shell script with highlighting support + FILE *preview_fp = fopen(preview_script, "w"); + if (preview_fp) { + // Write a shell script that highlights searched content + fprintf(preview_fp, "#!/bin/bash\n"); + fprintf(preview_fp, "file=\"$1\"\n"); + fprintf(preview_fp, "line=\"$2\"\n"); + fprintf(preview_fp, "query=\"$3\"\n"); + fprintf(preview_fp, "if [ -z \"$query\" ]; then\n"); + // If no query, just show the file with line highlighting + fprintf(preview_fp, " bat --color=always --highlight-line \"$line\" \"$file\" 2>/dev/null || cat \"$file\"\n"); + fprintf(preview_fp, "else\n"); + // If query provided, highlight both the line and the search term + fprintf(preview_fp, " if grep -i \"$query\" \"$file\" >/dev/null 2>&1; then\n"); + fprintf(preview_fp, " rg --color=always --context 3 --line-number \"$query\" \"$file\" 2>/dev/null || "); + fprintf(preview_fp, "bat --color=always --highlight-line \"$line\" \"$file\" 2>/dev/null || cat \"$file\"\n"); + fprintf(preview_fp, " else\n"); + fprintf(preview_fp, " bat --color=always --highlight-line \"$line\" \"$file\" 2>/dev/null || cat \"$file\"\n"); + fprintf(preview_fp, " fi\n"); + fprintf(preview_fp, "fi\n"); + fclose(preview_fp); + + // Make the script executable + chmod(preview_script, 0755); + } + + // Use fzf with ripgrep to provide an interactive UI similar to Neovim + char command[4096] = {0}; + + // Use ripgrep with an empty pattern to search all text files + // and pipe to fzf for interactive filtering - now with fullscreen mode + snprintf( + command, sizeof(command), + "clear && rg --line-number --column --no-heading --color=always \"\" | " + "fzf --ansi --delimiter : " + "--preview \"%s {1} {2} {q}\" " + "--preview-window=right:60%%:wrap " + "--bind \"ctrl-j:down,ctrl-k:up,enter:accept\" " + "--border " + "--height=100%% > %s", + preview_script, "/tmp/rg_selection.txt"); + + // Execute the command + int result = system(command); + + // Check if user selected something (fzf returns non-zero on cancel) + if (result == 0) { + // Read the selected file/line from the temporary file + FILE *fp = fopen("/tmp/rg_selection.txt", "r"); + if (fp) { + char selected[1024]; + if (fgets(selected, sizeof(selected), fp)) { + // Remove newline if present + size_t len = strlen(selected); + if (len > 0 && selected[len - 1] == '\n') { + selected[len - 1] = '\0'; + } + + // Parse the selection to extract file path and line number + char file_path[PATH_MAX]; + int line_number; + + if (parse_rg_result(selected, file_path, sizeof(file_path), + &line_number)) { + printf("Opening %s at line %d\n", file_path, line_number); + rg_open_in_editor(file_path, line_number); + } + } + fclose(fp); + unlink("/tmp/rg_selection.txt"); // Clean up + } + } + + // Remove the preview script + unlink(preview_script); + + return 1; + } + + // If options are provided but no pattern, run regular ripgrep + if (args[1][0] == '-') { + // Build command to pass to system + char command[4096] = "rg"; + + // Add all arguments + for (int i = 1; args[i] != NULL; i++) { + strcat(command, " "); + + // If argument contains spaces, quote it + if (strchr(args[i], ' ') != NULL) { + strcat(command, "\""); + strcat(command, args[i]); + strcat(command, "\""); + } else { + strcat(command, args[i]); + } + } + + // Execute standard ripgrep command + system(command); + return 1; + } + + // If a pattern is provided, run ripgrep with fzf for selection + if (fzf_available) { + // Create a temporary file for the fzf preview script + char preview_script[PATH_MAX] = "/tmp/fzf_preview.sh"; + + // Create the preview script as a shell script with highlighting + FILE *preview_fp = fopen(preview_script, "w"); + if (preview_fp) { + // Write a shell script that highlights searched content + fprintf(preview_fp, "#!/bin/bash\n"); + fprintf(preview_fp, "file=\"$1\"\n"); + fprintf(preview_fp, "line=\"$2\"\n"); + fprintf(preview_fp, "search_term=\"%s\"\n", args[1]); // Use the search term provided + // Show file with both line highlighting and search term highlighting + fprintf(preview_fp, + "rg --color=always --context 3 --line-number \"%s\" \"$file\" 2>/dev/null || ", + args[1]); + fprintf(preview_fp, "bat --color=always --highlight-line \"$line\" \"$file\" 2>/dev/null || cat \"$file\"\n"); + fclose(preview_fp); + + // Make the script executable + chmod(preview_script, 0755); + } + + // Build command with fzf for better interaction + char command[4096] = {0}; + + // Now with better UI but using compatible options + snprintf( + command, sizeof(command), + "clear && rg --line-number --column --no-heading --color=always \"%s\" | " + "fzf --ansi --delimiter : " + "--preview \"%s {1} {2}\" " + "--preview-window=right:60%%:wrap " + "--bind \"ctrl-j:down,ctrl-k:up,enter:accept\" " + "--border " + "--height=100%% > %s", + args[1], preview_script, "/tmp/rg_selection.txt"); + + // Execute the command + int result = system(command); + + // Check if user selected something + if (result == 0) { + // Read the selected file/line from the temporary file + FILE *fp = fopen("/tmp/rg_selection.txt", "r"); + if (fp) { + char selected[1024]; + if (fgets(selected, sizeof(selected), fp)) { + // Remove newline if present + size_t len = strlen(selected); + if (len > 0 && selected[len - 1] == '\n') { + selected[len - 1] = '\0'; + } + + // Parse the selection to extract file path and line number + char file_path[PATH_MAX]; + int line_number; + + if (parse_rg_result(selected, file_path, sizeof(file_path), + &line_number)) { + printf("Opening %s at line %d\n", file_path, line_number); + rg_open_in_editor(file_path, line_number); + } + } + fclose(fp); + unlink("/tmp/rg_selection.txt"); // Clean up + } + } + + // Remove the preview script + unlink(preview_script); + } else { + // If fzf is not available, fall back to custom implementation + printf("fzf is not installed. Falling back to custom implementation.\n"); + run_ripgrep_interactive_session(); + } + + return 1; +} \ No newline at end of file diff --git a/ripgrep.h b/ripgrep.h new file mode 100644 index 0000000..72b5223 --- /dev/null +++ b/ripgrep.h @@ -0,0 +1,26 @@ +#ifndef RIPGREP_H +#define RIPGREP_H + +#include "builtins.h" +#include "common.h" +#include "fzf_native.h" + +int is_rg_installed(void); + +void show_rg_install_instructions(void); + +void show_fzf_install_instructions(void); + +char *run_interactive_ripgrep(char **args); + +int lsh_grep(char **args); + +int lsh_ripgrep(char **args); + +void run_ripgrep_interactive_session(void); + +int rg_open_in_editor(const char *file_path, int line_number); + +int is_editor_available_for_rg(const char *editor); + +#endif // RIPGREP_H diff --git a/ripgrep.o b/ripgrep.o new file mode 100644 index 0000000000000000000000000000000000000000..9c852efea096d4437d50470804e6e24363b1d26c GIT binary patch literal 33664 zcmd6Q2V4|8*Y_YOh$z^*jtGiMS1j1DpsRuvY^b=vQWRL+BA}umuDT+YtJn+na_!fG zg(4QPqu48U6jW^2F5k&a!p6wzz0dQ0@Au^=JIO!)oSdATl$pt{Q`|jzlrb>iNHE|! zak>;iIW8kc7k3k)Zd^^S2Ino&K9QB6=mRaU6#)G}}Nus6*U9=Y^ ziPe#@(oi3PaRkeWMkN%njbN{Z$X=2Jy+(;EbTkp_z5b!NSiA2se6qDCCKUlHRB}+P z@!DI-pIMrGK#>|u$7(WET_g#KNM1q`l85w$OD}CUrMXZkrMV~$`P{Q!s8v7q&VMcQ z{r?3$*OV%=b3&rf=!7I>0o?X3+HAVp^f$hs-_I@Y@ZVT7K2_)@RcA&nR*VcSt)>vP zjZa0Noai)Kp@S2I&w^@9alspY;a2g5qb1sy6p2>7OQQAOEYW%5(o|5K@Oh`tz z);&iOACtqWO$F)C9-_(6?>s1&EfGZvnRxa|@J`m2NkRVp3oFJIx;X+to0@&$r(r2*r^!&8 z3lY&`^~(V}#X%Jo;h+fel^jyYl)9vNX;|SB-_0b5K~7*6$8!k+U$R7! zSnY&h4=mOo2c)L)NCYVhlbe#1CYbg|d6vJFXHio6YKhQa>u1RoIQ&Y(QY6NU2KZGe z!CIR8utpVFmZ*gNoo*1=$I|kbCX^iHC-H$30-;B>CXleRlZGopz+{qgzY;7siC;)~ zKu1ZsrN2rMYB$EU#D4R!gO438^#=5E_Y#ns|~_oO(7WxYPOi@ z9AoF?h+1w6BCGsLB=le>9(piImlqEt>!WerTA3z$*F3idW6|T zB#SfIAT$zjhPc_0Xm#SXn(M+4O+^<@UAhPh5RncekrU@}ttL+_gD#xf2FAG{gp9b- zv^a-`DJR}jshFrVg&x}giFLNWy)u|KI7RuJ?3 zTnAHity1&Q!u8AckQ()F1P8(P-K6P{+xL8@46@3Y3Xx|%6``UmP2LSq6WIoKZMtZY zF8Way|KUU9^@i%Il&wx~QWr+Ey2J(?un^Xn$RFs4hBM7Y)`$BXrRyT{Kn~ zovDk?(?yr)qRG1GW?gibE}Ei?X6T~Xx@e9rdR-UI(?#=j(IQ>+qb|zb(%DxRwa`Ut z>7u+YYNLxf>Y{CRQ8!&wqKo#|MThF5qjk|>T{J=$jnYM9bPbJI~7an4B)F}R}@vNXxUC22FdBxoXpOH!1Ww@b`R5%XfjyqRKN zhM1Qv=FJxK7K(Xi#k|XKNziPA&-lFeS|M^$a{!VCCpG)wf@V{(`ph(>Af@Gxw_1{a zm=p{kG!yoJs2&iSr7=QP2{98KgE^utjy{VvfjJ{lm_B}ZAfS^aNnlovBs3OE%9Jbt zXj|rD2-4zH1?j3WSsF83O@VEK5dUHGg;+3&qAeYs@#6)OfyiyILHbTQ3Ed(v$*Q1J z9=5hvKGp{2<7uG9CTO@MF;Q@z#H2h_4Ycr;aKB66^H~6mxm8Cjq75p9T(7jn&J78T zPem8lq_&0%b;=YN#|w(V?MITp13BR6X`GQzpXi6MPThc(3Hi8X2|_6_(a}7^5*@T+ z`>@1Ir{abd}-O2H>Z6t=TS>d!rt zSg*`al^DhgWaueWM(n8=t6#U*T+_c8xlsdO6(o!{!bU+0sesptn- zy1Xon4M;Q<>{Jb6$oC7TBxq2)y)YWot;N*OZN=V5Js8u;Eok+hl!_PX1w)C|n}8BA zRY(dcYCcUzsPylpy-7keKupG?FCl6UW5GL!3BX@^`=(L4(~DiNGXb zc6T(rd@)ZlhG z=KV5D*FH<*2wc%B^&m#9g5o->pwz#&%D*oauR&$NDq{7bRSbnDiU?8`Tcr@pK&)b6 zt}&;rk^>3RDzF6?4PlV;A6ds1Dip25LyTAl#dX#}sef;se_twIgUWz)#Og)sJO-Tz zf|SM9IS(+g&Jj)0(ve>_6^=y8Y=`tK>G$1*V`514QjkV0xKe}zI_AO z2(9MCMu~WH_`AJVf_px^yb#}?;FlMYgpnWd3yiqJh*oIEPF-?F@8dvt62R=Ben^%! zLkgJiDDqh-xT=uUYW6}MU`tdL{Vc2y48_1dZCRif(d{)|v=olHCK<{4rMmyGaz$&5 zD*sbkVJXrC!cr8UitNLwof!>(V_!2QQM~_vr(2RkzQSV}S)`=22ekIe;D7Rf79L!{ zQ-e}Bj@O0GOGOtLm=$3jgl-W)?a@PKVEr_h=YHw}9R*EX|2?I`@1@lKJ!Qb}Dag}* zqb`h}-%5Fsu#;1xZQUP|?JF!Yc?OSGNUi z@fdAERqYcn4?oPLnxfmc|G=TPsPOa<)lsq@{4gn_wxA)5bH&N$KFl&dPNL`mpq;r! zh3uInD4_@vq90+83?@M>;flzkiSI&3i*IUoLEVu2$FD9B|A$pjn9Be2R~P!_mGYti zSpynGtRc~|uR_qPi+?3CUZBH@t-qA+)df?%*co0h%J7tLKFuCIclh6%#4}K5#HXSQ zj1RPV2e%NwUr*wM@{39QA5esz7v6cnE;AY%RimZazr`kBF<+b z@Y8%o;D0=y`M~4L|9(CbTJ(?Rv!4zR=r){^Qr|~#oPrZx1do>~lp*qP-no-QfNZ=& zxH>cxxgN)vDncUAvs>Oq5!8$iQS#w(6(16=R7pcaWdS@CQ3V64j8>{-VfMV2oL4Jl zA{HoDfK>SnGS&+|%kfSi{`lqf`MfPv_&S56OEfLtM^1O$W!vMQQ#E%lb~ z0&gvOkC1S66eR<+1x0zgL6izYds^A^-Qjg;s9YMr!xq#}9TKYI;l-&`5zPlGB$V3f{Z((Q>tdR|d;ML+v?h^g^EWuC8;TqnkK!;p0QXgb%)jbpUT^t+eD20)ILn zTpBLt(1#B4mj}o=^ugN&p;E5a0hYX-f(w!bgs8+%iVS)yIIgdphn7WvrhcI^9ueix zr{OX=RA$QyAE**re(<1fAla4|gf-&>N_6G9iX>*Ogznf zvkMlq<~VO9%o46d6z>C`26cyz^9)jg+6)#l;sZo=awtT2m9gez2I7lHBBZ8peKX|NI8?+CE_M_)Lp0`ukf+MJq zU;20r>+e1iCOE!dcxW{7(ZG;Us6y}pWFW-hZDjUA_E1j6`$t4H13f`b2$B;L6fRfD z;0O+Q6ohW*3MQ9<^@X7$DkAVB5kFF{2(VMgf@DzQJcyMhnb)O0>G59)R+JsC-~Zlq>*FXDFa4%2LaR zhM<8S%8MLS76m9Dgvtkn%Kdnso*w>s;zB-gl+15Dlyeo|$yDTgZQXldnSY03%5M=Y(JAv#ViQ$z#Y65=6&ybo_Tfw#00 zP)mMfdsrJ~;b_pJGc4rj3OTq!j-=oNDNqgxwuCFH%aUH6`AL(&BUL2Jl#_)jWk@d6 zDJNmq#Eig6#l1M z$@8S0|MM2)!EI2lnsVe|pLh-rTo;|W6WZgCmNULd6VX_-MSeZe;~uuOB*(3Ub5>x~ z09j~A7;<&q6;k*q6dfe*C(V+;RpS{FSWKtY2Jv_c^1s1=&Q zV?({%tF1aXH#PFW;m8B#H|^}g*37E4ym|Jz8q@aoXmGMj^DUz2PYp{NlVD+Y)Xm3j%!&T{8dcQp?%uU`S2L%RoiCY`Z*+1=-U?;l%R6>eK4f)# z+Fto&x%~W!_K^oPwOiIcu=L~OWBz68zV(?j_vxmi-3~7tWIy}fe#d)`{smVn1UQ@h z(Wq9}Ec&CkrSwqwBOP}5wv90w)n$vJ(euK;GHb6_z8Q9K@tVzT2R@i> zI5y6;LT013{rXprYf|;7XXd6A7e<=b*y~m=IVgjIT1&VKecrAuVjDhRB(WqbL*uhOD&zN2khVYu+^k7A6pfLR8V`2U!SyK z(8JFcLl2zUKH}YO_ovq{);(0%d*YGY2@-@@w9~d^BcTNG+w?aysPQwqt+*OYP|~jdG48UH*dZ&^QB=K$-|tUN2;B= zf4^{C^6ae9_3DjquM`vCEq+Ycq8St7KU-USKiRkLWZfM-=4MW*IKy_3XR=*-@59Yo z-MQm8KC097r%QXc=)^f!I6vo)t&Ur+dTu>2ZgcBD+Hdb*c5C7pkNNf6?Reqz`0ow- zJ6X9d+-i4eOS^fw=Jyq^7KYA=i7B61)8*4Vm&tv5ZXD2Z-=v0qpF;1gOiDZ+(KXIN z-L+-kCCi=TTIGDStLM8W@c!Q$o*P=NIV!Wda%*!=!<2=OXK!e=WQw6@hX;K+u1T%4 zL){>A)9rO1PxQII*1zNA4;$*aPR>l(DDAoRUU00feD$-S!cj}BXxbl@wAy#_zGt8PO-Nexb5nSvd5P$9Op4y8Ft6DMy_-3aq}xTTQ@2p)~w^W zeKp3#*Jx7x#rAO-FKb-uW9>2~;nk&bqcOpAs>FWE^j*WUlV@}di2gF9%NE$AVL zyZvXG=xV`>>X|EV?7BA5#&KlX@Y5M))j#$r7x;#Ai5ar<+C%xxfDgv^{m`MA+mt%H;{XR-G$t-yN;9$}=YCT0&M~ zVEy+)#}}FGE{v@=A=Mab78S>_+Mt(uCt~b zxh&s4>21`P_7Bcg@Xrhw^EPcx+e)i;-6=46-RoBBB#YJiuh_*FwfS_@Z2a+cYa91` zT-KrKz2oU`*M4z*kYc^k_|cVHmD3+)&OUj4m}T93i(3cHH80JYOj-Fvxgq`d{Lhhn z~8#MwC{@h-*>-DnqwQYq_^+NH`18FgDx2_eD~b%k4|3wB8FT4QR(W#Itecf zE>B3xtCG;8=kq(6=N8n+^8JweF=;}xr&HJ2k4kvwwLbqw_QF-~c3mDcpzDMl`+0xs zyNA1G)M#C{Wy6S9FZ$g+mAzs?=Iv*d!mI7gseW*=_CV$GreQNHjGF4M@UL0-#<%3U zeQeGb`*z=V=dfw4>1dIYG`|mw) z`1tz#dav9a%g(1R{W9~?X0x0=78_Qpk~?}oiH{9#YPhM=@FuDC@)w-G9KZ!ne^5hp zW!{#hWkpSZIY*f~Zr)ktN5_NNmu)Z3kMaF9cSy^+_l~_dTztEBnrd&x!XeTpk-I(a zT5U?Ld)4*oW*h4_okrR&f7wU%kb9e4c5$`+b5gP|ySh}fd)nu<^C|=L#iRW4=C=>H zccv($%ICm_{fe(};WhJuT8z06qqcl-Z-VVWhp-`;!_~e`3jMcVbW`VeF0Zdh7^sQv z7JO?_7@y~Tci!P|WhYc<_t+LpCK}E}G#~!#YxP5tN|6155iUT|Q7iU&dxq9^uXcCk zvjdYy?Y#E)jwyAjHeKVHIM78Mn;c={+2yg@%FS)6)hs)%ceUdN<$Ky0&sw*@$QFXE+tj7DOd4D*@kP(XH8RjZ89$BB5_%fUvX`l z3-%1TTioVdb&pdv=LS|UbnaSVxntJ~8!Ok8ua|zAnclzU+uI%Gd!C%X2pbg7(e?Wp zw`<<`ZtT8F+m60j<9p(ZbAu6UlAT)|8=jd_Zs*|3W1^})ah~lwu)(AHL-)o`s?bVv zVD;#L+JW9TocqjcVKdJ-$h=qesJc(eyfZz2vFQqzeaH3&8jSZfa5+(Z$cR&Jmn_X* zd)L_E+&Q*--;1t(4J@l$*PhgAtjc0t9ghuBvx6`6cbwFHOOMBfWj7?1>z*q)y`lM~ zy@_j<$Ewc1lK*k?ua}oBf}B$y-#+@rxZ@q4^jm{EuW_-8=@D3NbBn^lK)13{z4M1m zJu`LZddY!5&Q|pL>XvlmeBI{RE!2kEjN$G_&RQQdi@s>S`LE;iVvfXAbNbxttM!QQ zPNN?jv+d?ocF?4knJatlpHpvLdiSxj0xKWNi+1eT{Xp!Wd*g$Rs~J5QxII(a&G6tr z?ukvoV~0jn|D4&W`{|x9Td!y`eXC>B$|I{jY`4Ds2xY^V(7SGFMo%luR==HfP8#c! zTyg#Q`xEjT#vl8XTH{G%Z_n*H-<;pb%=XV4*{yTKvokJxq{Xj2GU|k6=(`7LJ|R~u zqNmxetAFE>m;YXkRc>4_pRV^BoH-D&Ox;{tVUi^0z?!*RPiK$*T};`Y z<7vqkiMP|{%Zrco@se(zKI^c}CC4g-mnzNa*ke*sjoO0_&8=p9X2SC;ZLK{D_l$UG z{C%vWuc>`e{ockk^Kuq7>in>oU4_4zuirOS**^Q4#o@WrY@D|?@T+Lm$EI-HS)aBS zDti@vIP`3GgV&2%r}RAAux*_`8>N4}ls3I;RpLW&c8MV!aUbtp{ zV@l+dp3)g(qkLZMc_jC3lQL~e@B+ujtJ_Q;oqeyi%`9_Q+s->S z-t4RH{`~Zek#RSU_qrmLyuZ?M+|7>fJR8=TJEgtjGfTJCne!J#jSMnw8S!%WqUD97 zt|u>9-}Ktjk68y-wLkm*c$-EGj@LGR9pY4|@EQJS)N7L(#m23qonxK0G}vI*qowJt z#bY9$TXr4gKjL%O^%ah~A2|5xhRc;nvzwfqSgbLsI%ekHyh|;+Pu{qxqsfD>)1Q3$ zxNmUm@#Dp@MzWNrF~_G=wLCNBO>vp*Bi)#JJOaMhhJtRM@m_c*{8n2F&C>y2%QUOf zc=_KOha}u_k2~@A+I*KTgBoic-4&nwo5p-z)u?v6wB5F|R;*U0Njh+5GvfHZukehpzN9Q^Jxqp?SS75@z7Y>6pvlUlc%32@ociO1tk$Ptb)ZI46v+V=V zNylcqdhQjZzO=M_`^DY9Z0U6C#9NhH`6?0PCmhXvlHFmzeY>rnu5IgTx4VXR$H);b z=d`tba|63Ax^l|C#=)x*-XR07KAn2#R!i?ep+%p%_3h=dXYKaxTBUkJn_TC=%Nh;# zS+c&oi%(Xky-lhV^xC~TzeYm+<(XCAcz&HVD7vQ2-pRvnq=nDh-K6r?@U#=oCUSdC z)E;ZAWnDYAYf}C8v<1q*fCl}Rd*56C&fRCz?tbT@`cydA`mtg`@uR(+2aP=$GU;Qw zqROW!$Dez?J(hoIkKA=-yZKW?w`9~(?x?3c_ zU1y)QS?0g#)U>eN{^gs>=M?pSVgGmky7j&8RXE(lXXuGP))!v8Z})uEpn^X4)2BA< zGpyP3g~OcR*<7A*aIWv{CA`g^9 z&XXgKCa21->ScQ5nPpjDyO~Q>7xy0a>A1DilzfkTt=3`D&gON`j%Z}y;XZP(b>VHd zv6k6)onj65?eAjhHF9@)`nNANGYoBq4pmQXxWudD-mK(c4}&_lpZa8MyiqpUafV67 zCpWGfxfEMwWv|7FQh&+f(Q>!FYob>NJ=>6Qx9N4&LHiAjT=Qch6Nj%Hc-iLBj+C>t z>bZ^ZXfWn)kJAeem?+oZA9>*5$bl!1b*a+o!|r)ScR#mQ+mA44dwRve-IuSgzmdYN zUOvL%LbszE$G@GjY0V9*MP^s`Gz=}+`{-`f>7T9E{JC@KriUq=7JVzH_4EnY;pErQ zYRQ;-j_(Ve9~*k--jL$2AKn%{&3$?-_wA;Kn>HPL{rY3p!`H9h-j}wx^7fjhW7Dxk z&HGP@`S#{b(VIz8Lk~HHEt=SVbB|eWMdRZ8Pd>AGf#2dTb()&H&;Psi)$@T%&$igH zx6;cw?GIf`ddcsX*R@vw9~h8-F=6zq{h!oJdkwbDQVt-Ihl@T z-6yWOTBgz7nnSIuUiPnk&C||0B%pnZ>$&paVaX2?b}rq$x`$S?pla`mgB|+EMT88ys#j{6dT9uLaL8e_k~`a9iMa_bXQG_RVYr~Nhf!;%FJhnRVH9c(Gch0tbLJh8GH+TzT z)3dL4Gv29{y|cX&@9gO8;^^$y1|5dyc=$udE`R{L9fJ&nk@g!f>1vRNg29A=oI#X@ zL0vOrlX*a{2N?Q8AsKyisbn#|Ot*^V$}9(lnAZW}5Rkof`AbUjM<5(R6#6JBuPn)* zgm4H$&>Tqe4F{G%1XTA5lnJ2+Qoba=ivh_$BII&hD4H`%@`K8ud>)|NIDZ{_6;ARc z@rH(rDhfIv4l&FN^gNAl4D(F|0?OADkV;0}YvD8sOEDxunG8drSAGQ1kum5a&J1-D z1fi{Blr!Y;Vt~`+V#xitd)47c+Rwp|6V3wslwrtK`U$HGNEJ%|WXxy*S2zvzQ*hFQ zx6y-l(u1SZ5vbl|xS}BV6kO43@Y3oX2RPz)L>&P^@G-c~hQHGINqTVPV@S?EEJyG~ zz;@{2@6&^)>cKMsNAd>>=b*5!0(Mgm|GpkPUl0CD4~~8YqBJ{v)q@*C`%B}S0FLxe z!>%QaC6HmGhwrQh&(wo=(1Ul=gZI{h572`T)r0%$!2|W+WA)(CfFt`z(ZNm#!aM?3 zjUN6YJ@{Td_+dTxQ9U?^-+bEpa}iR7QsxUkk0Aay0vDo03H;ty7QjWI*XmqgkW8iI zBK$+;@B;z9zHoxUf2^;6@L1nKX-Fui43=+oSfEQ4le{h&QfD6Pn6TFGz>f*U41mA>lQg1z+-bwM%JVN;U z89p3E5rXj5Oo$;pY5oZ@TX;%?+Kc9M6wZm4pZJ$CPV^!5k+q+d|B&I6@&$V2zhU?v zaQd?zz5$F&6o@|6aJoFcvihL!?$iACI9*E*zahgPfzwU(@a-8snrBcz->pP})kneb zZ{zedieClFk^Wsk;Z-SoCxz4gBNzsF#6F)e&jbMwkUo{+kI1*hIN_tiz9@8}__RJ= z4Brf=M^JoPek{Yc!0A6IJ}rMU!>^CiyC^;_|1!h3#A)TOZyipDr1_HX!{^myE)gh1g)fhc^3We98_*L=#4Q11~9fjAV_#PBa>!YG@bjv~X ziJ@?F3jd040Z_eYi$VBp(bp~@Ae?TO2Zhu8L<+A1Wr&;=6i)N+Q8>-7k8eF#eLCyG z$Lql#>%nKk_l8hl<=@kTSHR~W5TDkw3dWJ!AeUK>{ihDar~RiHh134olfu!x5wV*u zBcI@7C_Y*n2|kO$X*sJX9If?)pGM&gDEu6S({kQWIK94?!~1q*A6iaz3a8~*QFueD zURMgI{bUY>)ACnRI4wVg!s&5wlfqF`h#ekMI6W?^pacZeu14@j_$d@_N#W@jC;mX@ zr7Vh1_xpKN0|L?01MBI4aik}`UUZ^x+WsDl9HRda zicgQPWfV^P{|*Xo3Uw1XnG{ZsyEhb0`}q*0Gz6r-4g3)~vnZUdcP)j}^9jD>47Q9=;ngE(9WfH|Bd{ob{ja3_l(7#>BawtZm*JD~xR~N2mn8gE44;h0je7V882$;|-s2R%F(p5j z;a|f1JU#ptXpx3M+Dq);7UQh_r3|0gKU@$08N(<0r@!^^yP!=BrB4CYzc0pFeIgnD zH_V@=hi{BFLzH}?Pc@9Q@_iXT(I-?7KZ)TJeb(yXf1q%BTsNsD>WTDe0e{4QhEO=o z&!=#DJ~Trl2uKc%*QIcJ9c)G6mQaS&+aBY@Psq6FM)B!!F@(bD^)#Ns>GgCDBcD8X zUPSTfakP@*d!YtG*r12MmBP_dM%uNTkuw|1IY{y8debPJr{tWYa61YwX5{b1@=ejE z5CTfl>sn)s6FVQqe0x3ojtu`e=DSmTT7M6QUx@i$diXvJ-wNLk`0L@1Vfc}luh7Gf zX86-EKTZ#SCc{6A`SbMf7c=~?n7>*Ne}ZxpWgpu zF#HynpH1-{DESW=KDnPP(8Di>DuY1U)eXz9gmGjaT7ENz-xu?p^zc0x{&39q(!-ZC zd==(L>f!&v@K0j?GCll#4F4?Vr|RKfXZYm2Se_pK7luCq-wzw&2fnO58(^H+e;ejE z(Zlb;@b_YVFFpJKhHrxJw?p;tXE6Lqm_Jt!e-(w(`{6wl?g&0a#?f6yeibY~pTTW0 z{+W`4w!lPAc~lt$WKVkCY>aVYPr|oja8j=eB?omK;matT-v7r?I9i$r|05&6625OQ zi#81qke>8DvmS+`ttFAug2ItVf;(fJw2SEPO7YPUC;VP|@B;IO*(bkg4G3Frw z0qIZkB|Jh!98Ix=KZHl<&-`V)01I+x{#6R6`>{8=`G-K-OXf*$j3a&M{?agfGEXK_ ze0m<+%<#!Pxl0fK48te$WUe0mD~4~4{h^rRJ3$+W-RfGR*6P~Z0rOj69JQC`_h9&B zp6N^R>GqDKaN4iNQ8+zL|77G7e@kKT*;vohlpK1T-k@;0f8R24h#kH$IH|WR8axo# zes`g8dYpPvIPJID7%u~|4B?NA(<>AoMTtIz6i$!RFBDGOvy2rKhCt*K{Y^2B^ry#Z zZ9TXpBZur;np1pwzu`dPJk&w-mryu;AAy$*4s{>i5Q6vF}OEQUtw?sPTyp3@?3)0kMzqp><@1l{sOGO(BY6r_|37N74ene z23SrV2JeKOk-YaL{6uX3Rt!G~*V~1`Wmvzy4DN#MQyHAx zch6<;##o;f3~q_jTNvC5>m&Sn4`ol`SCAlmg5jgHeJEUF@G&@jkHH6FJD}f?M1k1Z z6WgD>za@ALtWP=I4+JOesmkC(FrQ~|^4!>t!7Jc;T^YO;PWNQ+WGvr{!QWzB%HUmb zf5{nqEVjc$2H%V2#54FiY_ClWJ|5${8Jx%Mdc@%5J+2|HhuBk!^)zMhYgo_948B$D zKCTvnXJEV`gD=N=G+}TL%(r9kr?}o$435@v6i7RW{%5cqx-fk5{gWtpa7zR%f)#tPfUJs`iG59d7&pHP0gX`VJ;94v{mBHI${4|5t z$8xSQ_0xoVo&rRE1*E+6MN2La8mDb1}F9;&(DbdMV6x6bC^%?28~7hE+dE7^A*GI ziuslC%@5I&*s~FX6MGJ0@CfWDQj8OQ$T{pNhM$l9N6X+hP(cXG7~Blwe=>M$-0w#i z+z{jE82kd(^DcwCVfn8Zd`Mn1zQ>%~U~ z?}O(_6a3X1B7d3Ke6ALQ6Mt*U;AFmXXK*tA1Y(@n^8p@5(;5B|JTB%ld~zSUnc)i^ z1iBtzaN=(#8GIVH+Z6^Ue)x#N)A4wD!{D8d|W zR|da}<#=G6*o}Pu$DiSo_9_^hv@4FmNk7hG@L=38t1(XMCHD!t7(VIuOANjq+wC?Z zhkOs}EyE|z9m<&hXg8uKIY&qAc}k>lwK1RQnT&B;Mh-cj(3;_6Iyao*=i&7tgu!#L z|6nr-{foOw5QV4dl6iy3x5N>oKU!*BaJmVDkH+cd3_cI1?HPP6PCGL=*`K#&@H05= z#^Bd++MU54;B;>WFU0A74E`Rcy%_u(PSejVksZonKN-dFt76=r!O8QrUA#@!e^8K*}xII%-4gOhnCnZe0CoWbB^-N|EcvJW)E?I3!R z`x?$(86BpQ`oUGD5U;@`2ES!1wMV}y$k_)-RZ`C0PpRbW6>>2loVMg*t~=$ypusw z7~zwQT@o=Ci*Lx$wh5KRw+9^FZU|?P5RRuiu@HRDu_}rF5Mk@Lg#C~YL zEUo?wJRx^t3`WXBF(IJm77Rtezqb+daWlk3Dcqrem8O4k^pE9{{%9T}^%MQa0alv+ zj%~&AWIrRObmd7p6e6Y7pM&ckiaQq7kGhhrKL#*VzazIokS%{4Xr=X^%_OmWhIkRqN>_n6DNp>Tw7O9d$F5?* wT}U_tbbE%@K(;*cNp|i4h|BANJ~{3bqd$`rzMEHC`FyN@t|+GDlP&*$0Ge&rW&i*H literal 0 HcmV?d00001 diff --git a/shell b/shell new file mode 100755 index 0000000000000000000000000000000000000000..cb5cca43d8f4ec2f0aedbd17e317c71e5408e5ca GIT binary patch literal 266912 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 V+o!l{RQ{!r%4zo06{!2_{Wog`3t|8O literal 0 HcmV?d00001 diff --git a/shell.bat b/shell.bat new file mode 100644 index 0000000..38a94d1 --- /dev/null +++ b/shell.bat @@ -0,0 +1,2 @@ +@echo off +"%~dp0shell.exe" %* diff --git a/shell.c b/shell.c new file mode 100644 index 0000000..1c42d46 --- /dev/null +++ b/shell.c @@ -0,0 +1,591 @@ +/** + * shell.c + * Implementation of core shell functionality + */ + +#include "shell.h" +#include "aliases.h" // Added for alias support +#include "autocorrect.h" +#include "bookmarks.h" // Added for bookmark support +#include "builtins.h" +#include "countdown_timer.h" +#include "favorite_cities.h" +#include "filters.h" +#include "git_integration.h" // Added for Git repository detection +#include "line_reader.h" +#include "persistent_history.h" +#include "structured_data.h" +#include "tab_complete.h" // Added for tab completion support +#include "themes.h" +#include +#include // Added for time functions +#include +#include +#include + +// Global variables for status bar +static int g_console_width = 80; +static int g_status_line = 0; +static WORD g_normal_attributes = 7; // Default white on black +static WORD g_status_attributes = 12; // Red +static BOOL g_status_bar_enabled = FALSE; // Flag to track if status bar is enabled +static struct termios g_orig_termios; // Original terminal settings + +/** + * Initialize terminal for raw mode + */ +int init_terminal(struct termios *orig_termios) { + int fd = STDIN_FILENO; + + if (!isatty(fd)) { + fprintf(stderr, "Not running in a terminal\n"); + return -1; + } + + // Get current terminal settings + if (tcgetattr(fd, orig_termios) == -1) { + perror("tcgetattr"); + return -1; + } + + // Create raw terminal settings (make a copy first) + struct termios raw = *orig_termios; + + // Disable canonical mode and echo, but preserve some control characters + raw.c_iflag &= ~(ICRNL | IXON); // Disable CTRL-S and CTRL-Q and CR to NL translation + raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG); // Disable echo, canonical mode, and signal keys + raw.c_cc[VMIN] = 1; // Wait for at least one character + raw.c_cc[VTIME] = 0; // No timeout + + // Apply modified terminal settings + if (tcsetattr(fd, TCSAFLUSH, &raw) == -1) { + perror("tcsetattr"); + return -1; + } + + printf("\033[?25h"); // Ensure cursor is visible + + return fd; +} + +/** + * Restore terminal to original settings + */ +void restore_terminal(int fd, struct termios *orig_termios) { + // Restore cursor and terminal settings + printf("\033[?25h"); // Ensure cursor is visible + printf("\033c"); // Reset terminal state + + if (tcsetattr(fd, TCSAFLUSH, orig_termios) == -1) { + perror("tcsetattr"); + } +} + +/** + * Get console dimensions + */ +int get_console_dimensions(int fd, int *width, int *height) { + struct winsize ws; + + if (ioctl(fd, TIOCGWINSZ, &ws) == -1) { + perror("ioctl"); + return 0; + } + + *width = ws.ws_col; + *height = ws.ws_row; + + return 1; +} + +/** + * Temporarily hide the status bar before command execution + */ +void hide_status_bar(int fd) { + // Skip if status bar is not enabled + if (!g_status_bar_enabled) + return; + + int width, height; + if (!get_console_dimensions(fd, &width, &height)) { + return; + } + + // Save cursor position + printf(ANSI_SAVE_CURSOR); + + // Move to status bar line and clear it + printf("\033[%d;1H", height); + printf("\033[2K"); // Clear entire line + + // Restore cursor position + printf(ANSI_RESTORE_CURSOR); + fflush(stdout); +} + +/** + * This function scrolls the console buffer up one line to make room for the + * status bar when we're at the bottom of the screen. + */ +void ensure_status_bar_space(int fd) { + int width, height; + if (!get_console_dimensions(fd, &width, &height)) { + return; + } + + // First clear the status bar if it exists + printf(ANSI_SAVE_CURSOR); + + // Move to status bar line and clear it + printf("\033[%d;1H", height); + printf("\033[2K"); // Clear entire line + + // Add a blank line above status bar for spacing + printf("\033[%d;1H", height - 1); + printf("\033[2K"); // Clear entire line + + // Restore cursor position + printf(ANSI_RESTORE_CURSOR); + fflush(stdout); +} + +/** + * Initialize the status bar at the bottom of the screen + */ +int init_status_bar(int fd) { + int width, height; + if (!get_console_dimensions(fd, &width, &height)) { + return 0; + } + + g_console_width = width; + g_status_line = height; + g_status_bar_enabled = TRUE; + + // Clear status line + printf(ANSI_SAVE_CURSOR); + printf("\033[%d;1H", height); + printf("\033[2K"); // Clear entire line + printf(ANSI_RESTORE_CURSOR); + fflush(stdout); + + return 1; +} + +/** + * Check for console window resize and update status bar position + */ +void check_console_resize(int fd) { + if (!g_status_bar_enabled) + return; + + int width, height; + if (!get_console_dimensions(fd, &width, &height)) { + return; + } + + // Check if dimensions have changed + if (width != g_console_width || height != g_status_line) { + g_console_width = width; + g_status_line = height; + + // Redraw status bar at new position + hide_status_bar(fd); + } +} + +/** + * Update the status bar with Git information + */ +void update_status_bar(int fd, const char *git_info) { + if (!g_status_bar_enabled) + return; + + int width, height; + if (!get_console_dimensions(fd, &width, &height)) { + return; + } + + g_console_width = width; + g_status_line = height; + + // Get current time for status bar + time_t rawtime; + struct tm *timeinfo; + char time_buffer[10]; + + time(&rawtime); + timeinfo = localtime(&rawtime); + strftime(time_buffer, sizeof(time_buffer), "%H:%M:%S", timeinfo); + + // Get current directory for display + char cwd[LSH_RL_BUFSIZE]; + char parent_dir[LSH_RL_BUFSIZE / 2]; + char current_dir[LSH_RL_BUFSIZE / 2]; + + if (getcwd(cwd, sizeof(cwd)) != NULL) { + get_path_display(cwd, parent_dir, current_dir, LSH_RL_BUFSIZE / 2); + } else { + strcpy(parent_dir, "unknown"); + strcpy(current_dir, "dir"); + } + + printf(ANSI_SAVE_CURSOR); + + // Move cursor to status line + printf("\033[%d;1H", height); + + // Clear the status line + printf("\033[2K"); + + // Set status bar color (cyan background) + printf(ANSI_BG_CYAN ANSI_COLOR_BLACK); + + // Format: [time] parent_dir/current_dir [git_info] + printf(" %s ", time_buffer); + printf(" %s/%s ", parent_dir, current_dir); + + if (git_info != NULL && strlen(git_info) > 0) { + printf(" %s ", git_info); + } + + // Fill the rest of line with space to color the entire bar + printf("%*s", width - (int)strlen(time_buffer) - + (int)strlen(parent_dir) - (int)strlen(current_dir) - + (git_info ? (int)strlen(git_info) + 3 : 0) - 8, ""); + + // Reset color + printf(ANSI_COLOR_RESET); + + // Restore cursor position + printf(ANSI_RESTORE_CURSOR); + fflush(stdout); +} + +/** + * Get the name of the parent and current directories from a path + */ +void get_path_display(const char *cwd, char *parent_dir_name, + char *current_dir_name, size_t buf_size) { + char *last_slash = strrchr(cwd, '/'); + + if (last_slash != NULL) { + strncpy(current_dir_name, last_slash + 1, buf_size - 1); + current_dir_name[buf_size - 1] = '\0'; + + // If we're in root directory + if (last_slash == cwd) { + strncpy(parent_dir_name, "/", buf_size - 1); + parent_dir_name[buf_size - 1] = '\0'; + return; + } + + // Find the second-to-last slash for parent directory + char *parent_slash = last_slash; + while (parent_slash > cwd && *(parent_slash - 1) != '/') { + parent_slash--; + } + + if (parent_slash > cwd) { + size_t parent_len = parent_slash - cwd - 1; + if (parent_len >= buf_size) { + parent_len = buf_size - 1; + } + + // If parent is root + if (parent_len == 0) { + strncpy(parent_dir_name, "/", buf_size - 1); + } else { + strncpy(parent_dir_name, parent_slash - parent_len, parent_len); + parent_dir_name[parent_len] = '\0'; + } + } else { + strncpy(parent_dir_name, "/", buf_size - 1); + } + parent_dir_name[buf_size - 1] = '\0'; + } else { + // Fall back if path doesn't contain slashes + strncpy(current_dir_name, cwd, buf_size - 1); + strncpy(parent_dir_name, ".", buf_size - 1); + current_dir_name[buf_size - 1] = '\0'; + parent_dir_name[buf_size - 1] = '\0'; + } +} + +/** + * Launch an external program + */ +int lsh_launch(char **args) { + pid_t pid, wpid; + int status; + + // Fork a child process + pid = fork(); + + if (pid == 0) { + // Child process + if (execvp(args[0], args) == -1) { + perror("lsh"); + } + exit(EXIT_FAILURE); + } else if (pid < 0) { + // Error forking + perror("lsh"); + } else { + // Parent process + do { + wpid = waitpid(pid, &status, WUNTRACED); + } while (!WIFEXITED(status) && !WIFSIGNALED(status)); + } + + return 1; +} + +/** + * Execute a command + */ +int lsh_execute(char **args) { + if (args[0] == NULL) { + // An empty command was entered + return 1; + } + + // Check if it's a built-in command + for (int i = 0; i < lsh_num_builtins(); i++) { + if (strcmp(args[0], builtin_str[i]) == 0) { + return (*builtin_func[i])(args); + } + } + + // If not a built-in, check aliases and launch external + char **alias_expansion = expand_alias(args); + if (alias_expansion != NULL) { + int result = lsh_execute(alias_expansion); + // Free the memory allocated for alias expansion + for (int i = 0; alias_expansion[i] != NULL; i++) { + free(alias_expansion[i]); + } + free(alias_expansion); + return result; + } + + return lsh_launch(args); +} + +/** + * Execute a pipeline of commands + */ +int lsh_execute_piped(char ***commands) { + // Count the number of commands in the pipeline + int cmd_count = 0; + while (commands[cmd_count] != NULL) { + cmd_count++; + } + + if (cmd_count == 0) { + return 1; // Nothing to execute + } + + if (cmd_count == 1) { + // No piping needed + return lsh_execute(commands[0]); + } + + // Create pipes + int pipes[cmd_count - 1][2]; + for (int i = 0; i < cmd_count - 1; i++) { + if (pipe(pipes[i]) == -1) { + perror("pipe"); + return 1; + } + } + + // Create processes + pid_t pids[cmd_count]; + for (int i = 0; i < cmd_count; i++) { + pids[i] = fork(); + + if (pids[i] == -1) { + perror("fork"); + return 1; + } else if (pids[i] == 0) { + // Child process + + // Set up input from previous pipe + if (i > 0) { + if (dup2(pipes[i - 1][0], STDIN_FILENO) == -1) { + perror("dup2"); + exit(EXIT_FAILURE); + } + } + + // Set up output to next pipe + if (i < cmd_count - 1) { + if (dup2(pipes[i][1], STDOUT_FILENO) == -1) { + perror("dup2"); + exit(EXIT_FAILURE); + } + } + + // Close all pipe fds + for (int j = 0; j < cmd_count - 1; j++) { + close(pipes[j][0]); + close(pipes[j][1]); + } + + // Execute the command + if (execvp(commands[i][0], commands[i]) == -1) { + perror("execvp"); + exit(EXIT_FAILURE); + } + } + } + + // Parent process closes all pipe fds + for (int i = 0; i < cmd_count - 1; i++) { + close(pipes[i][0]); + close(pipes[i][1]); + } + + // Wait for all children + for (int i = 0; i < cmd_count; i++) { + int status; + waitpid(pids[i], &status, 0); + } + + return 1; +} + +/** + * Free memory for a command array from lsh_split_commands + */ +void free_commands(char ***commands) { + for (int i = 0; commands[i] != NULL; i++) { + for (int j = 0; commands[i][j] != NULL; j++) { + free(commands[i][j]); + } + free(commands[i]); + } + free(commands); +} + +/** + * Display a welcome banner + */ +void display_welcome_banner(void) { + printf(ANSI_COLOR_CYAN); + printf("╔════════════════════════════════════════════════════════════╗\n"); + printf("║ Welcome to the LSH Shell (Linux) ║\n"); + printf("║ ║\n"); + printf("║ Type 'help' to see available commands ║\n"); + printf("╚════════════════════════════════════════════════════════════╝\n"); + printf(ANSI_COLOR_RESET); +} + +/** + * Main shell loop + */ +void lsh_loop(void) { + char *line; + char **args; + char ***commands = NULL; + int status = 1; + char git_info[LSH_RL_BUFSIZE] = {0}; + int terminal_fd; + + // Initialize terminal for raw mode + terminal_fd = init_terminal(&g_orig_termios); + + // Initialize the status bar + init_status_bar(STDOUT_FILENO); + + // Initialize subsystems + init_aliases(); + init_bookmarks(); + init_tab_completion(); + init_persistent_history(); + init_favorite_cities(); + init_themes(); + init_autocorrect(); + init_git_integration(); + + // Display the welcome banner + display_welcome_banner(); + + do { + // Check for console resize + check_console_resize(STDOUT_FILENO); + + // Get Git status for current directory + // If git_status() returns null, git_info[0] will remain 0 + char *git_status_info = get_git_status(); + if (git_status_info != NULL) { + strncpy(git_info, git_status_info, LSH_RL_BUFSIZE - 1); + git_info[LSH_RL_BUFSIZE - 1] = '\0'; + free(git_status_info); + } else { + git_info[0] = '\0'; + } + + // Update status bar with Git information + update_status_bar(STDOUT_FILENO, git_info); + + // Get input from the user + line = lsh_read_line(); + + // Empty line check + if (line == NULL || line[0] == '\0') { + if (line != NULL) { + free(line); + } + continue; + } + + // Add line to persistent history + add_to_history(line); + + // Check for pipes and parse into multiple commands if present + if (strchr(line, '|') != NULL) { + commands = lsh_split_piped_line(line); + status = lsh_execute_piped(commands); + free_commands(commands); + } else { + // Normal command parsing + args = lsh_split_line(line); + + // Check for corrections before executing + char **corrected_args = check_for_corrections(args); + if (corrected_args != NULL) { + // Free the original args + for (int i = 0; args[i] != NULL; i++) { + free(args[i]); + } + free(args); + args = corrected_args; + } + + // Execute command + status = lsh_execute(args); + + // Free allocated memory + for (int i = 0; args[i] != NULL; i++) { + free(args[i]); + } + free(args); + } + + free(line); + } while (status); + + // Shutdown subsystems + shutdown_aliases(); + shutdown_bookmarks(); + shutdown_tab_completion(); + shutdown_persistent_history(); + shutdown_favorite_cities(); + shutdown_themes(); + shutdown_autocorrect(); + + // Restore terminal + restore_terminal(terminal_fd, &g_orig_termios); +} diff --git a/shell.exe b/shell.exe new file mode 100644 index 0000000000000000000000000000000000000000..dd9f0a6758209f9a1481a9f0222f2aaaf4a16e0e GIT binary patch literal 703573 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

    %crRal)mLL*DTM+R~>%S7qJA#g4xS6q9 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

    L@~Hj>+6L237o3 zOCoPYBIm8hj3}%q8BtTB?6k%(C2Bsy^P`?cfhj+WdI=l+YDDxUK3cyNJ(G`q7FOHN zx9i)h6);p#?JPrQ*_Lj=U;)jMEU3P|ItpK3eP|7YhSnHKt9Ds6PBV16h9GIKKk7nM zDQhf6RkC$^8I>BX*?INs>eRa#{pQY45^*ci(M87PcH}k2<&A11s~gaf$Y?+p03QRo zp!%xnuKt$Vcou>Yy$To_5kyFP&6+H##O$)nNbepRS>0>&B2h^M8GcE`vk2QCAyGyk zHP%63VvI{fWkyn)Kp0%<2vr)L8sj~P)YzD%6#&v^wIk-&7*u{OW;{lT2P6ZHz)Ay6 zr8ZvB7=&EVcmv-OZ)lO<0;4Lw#jX|@ZIBUmwOEB$#qK7uKu()i|J2yV`S?D;EUe)d z8xLs$Wyp{wE9EM2lbsChY;v-xjy~D6xG9#*;-;kl%trdsrVpEf5)YeRZH7T1pL_0& zPX*s&=w7q(X2QS9n{DLFuw5-~(Ye*4yafs^Z;{J)V!3ae!-ob~^|?1j@rlc*ma}-Q zJgeo>mKwgaC7RRSOYsbJhrPymzp2@o=5$#iU6w`n{u`@W!j%R~%Z-y@g97FvLb_Cp zkpw7yL1Pz&UFQk52~JQsUqU@4G^ELhCcfWVUazkQ*N7(RO&q;sob3dym`kVI+2lZz zfc}=(m`+0uG&$BJ;9GCVu_ou5_?Xe>np|jt3tYUAXo4;@x!c5r-J;Haw@F!(sMp_x zL5*hdxZxG=owDrj#tm!gu4P!$w5FaS)0$3e>I;-{O@%F;)^uf4Klsh?N`!q;zY)!# z13}EGl}$G`4fp~(J2$Qyo9^@~cxTfBPn`u#i@c(Wnx1Ux0>yNra^Lv*4eu&{eq-+& z9{l#AKRqO!g>m4O)(|z&Wo|=k7`-E!U@DAg@?#UZs`MkrFEm_eHJnZOf;F77X4%at zjL0|yH|DTI8VozVM>j@^;h;+`#Qw#Hkb6;!5w!_J z9#K+sCtb8#OR})}ndVr7&ouw(bu2#REz;kBHo`qI#iJHBFKUkbMa@q%rzJo`k8q;- zspe2miFK({&95{Ex>uT)GT}pfmJYg59(>^2bU(iC*2!q>)sxr8Hv>bS(`-GRT`dZ6 zaat9&IMkv7S31_>65*FxT&)1N{0ikp#mhigQQcdvaSDuooSJAD$DOEd15kl@NIRQ* z`PsJRb~JgpeWTqz0GE3<+Baw$xN3vCq!4onc^SjpZeFE^+a~jB&}7?mo9)X8HQhFv zSIj1=Q*=%tlkNKm$qHFW$Y)M$aaEq}xD8r}3f#6$wA;V=9#+@vKiLu9Xg^>_ zn-AEF?Q*H7*j~bLiTxQ>7ZZV5CDnvl##Z!3E7sV9zM`0pEA-8%+rUt=Kc-gUF)~+< zng|QMh?0itTRCi`+D7DXhtRf>7vP@Rhbenz-XJ6c5kFxH`Jv57))mQS&;s&CBG*+T zXKbJIY{L||r4Zk|Wn<($ZX3-ONqf5>?{Pc2qL@X%u(~?05O*HrbMe+_{nvP?=>DO? zavOGGgGsA?QZHu=sX|w<)QS=`Wh4`IQb+99=tx7&F^|}XR0(y0N@y@k+RN&D>K2$f zHr&}Qv;vtzE6jIyg8A;NT4Cqr_>w?6snB}NDtE1pF)eiINQ(>YU5qPGrZTSW=ZO1! zFs*M7woaxJV7hfRoz>RO$mVHg+ui{7#(io$FhmM1tVtqMi=o;M0KNkx4oj=V5pfiZ z5_J>cAH&PZV|d%jxcOyKf0T@aS*RzY7?Nc6KlbKEviJXi2LE6G3x8NJAo`S2qCw~0 z{|mh>FYqpcGi7|;_PYaIx!brdpG=s3zN;9X$H$T8drz;I`_ zQv$vYm^lid*D-gp1jD`TxlIj2G3PIS=Cn zKQfMs_!$qM;K>IS#dEmkj9TK!t#!4oc<$CcTu(e1aZBUGa~tFm56L7Rl1Drwi+D&5 z@vKf6h1YSYBCX*Z?I~?YD;p>O3A+;iV+xrWgi_EaTBkWMW2ZTm@s|2BJ-9H(WN>vi z2NwX@&Pf4CI4R&bm39Ce4_Frjz`CG4K^m|pXc|>O)52xkA;q|e(~$t2jx34PDM})D zMFFrYDyb4!PWx2vUA2OzcjtQv@(RYS%p;Adkq>j02h=PJi3035MMD8m)V z>EQ~v3|CyA)Wa2kwD{XJH+Vb#Onsg6O#LVIk@HD?8NW!8pHQBN6y@j^onlDR%J zjW^bMKcU5FeQ3-pxU520x|3e0i{;IUjs?*>#jhIungQ{LI+3!=>k-yy8sEK z3-ClhcL4yxF+g$M1pu4@?Imx10yxE|!YL#yi~?nYQAoHX8ASV3h{o{Wp_8%{O#61;pn<}E)5%)30@h$QD z5kGM&`cq^9W;(*TwU&8K<~+hwWrQ>qiNK=3Wy?%dC9a$RJH8)|DKa^bfXRWU1G#eO z`V&$A@<_s$qarYDR>R=3TEpr{KFv>1faV_X+)8{1HUiJ;lnY=Q@LWkr1FwLmwBcm% ziXu%Wif(Q(xH6sytCe7gkR8bW;2d%ubrP|o&ihUTA30Bl!IAZ%pDKxb8HrFTO%e9f z1E8Otdi`{7X)J2(K+9xMVBYl{FwLbCB>6=~*$Y=@N` zc+P}A4Mn#ujmSqgBYa9YIXq`$N8l|hJTq(V(4K;tWa)r#e2XW8A08)UXIzQ)T*uld z5Vl@Cx|@(jGkJJ4lZQt$d3aW*%twF0Q`+z#`m31sn|?o}Dz{(L0W_E>uQ_(`$f*-r ze}J!Y2O3R+M>h$c!!@7tc`nT0)EvwE3}a=DLRdElo{YF@Kp&o;;&#TNu(bF>KGGft zX36HjqniVdZVo)UIq>M_z_VJ0A3SMze~NlC8|I;T2y+Ri$1QQ1UFq%0F!Wl7vF;vq zK0GikP7i`YdFRPDCW%U>Hrq1F9GZL)*)Qp4;3HE`|C~io|r-9)iN$I?Tm7X*&388sd zn?&2UiC3O*jUKWVz*mz-B*Phzyi}WMTAG}nY##{yS$=W}BaSqB)(B2oL}Q*5=;>?MJ4KUH zV!cjPgqd-8Y~-`uCC5VBT?IVKEpQ#eEeza5J>-`YfW0C)rNo~OJPm_Ih|seZp8H^$ z5@m4BlE|B6);A+JVaY=L&FZ6S$m6(CHF6=J0YbhiIhNJh!^=c_YIE^I#NE32aFj+e3s|33D`&FH)Elz*PtV;-T;=wXDXXk1Y3OaG{9Z5Mm{w6pKG1va#ed zhZmER0rbe1ivu!fZZFtSdW1(0W_a{qhDXmbcvz?|4N5i}UbQ!;Gz(x%AtXoI<1LBI6SLiU5L6_=?P^QJ{>ItZ;c-kzF+?KB zAqYr|-<&{qGp3P5+^#vQ7DA(HVM6vFWQgxDRe|0D zmbwVxy+T<;0m+5p&`e#bHq?z|!O^@nS)`5JJ7IF|)u!Q9xS52@T;);L^k5 z=QrBO3$+^?6*Q8IRRs{fT_PLM?C)c8L7Zoj+4VJa10K3-A6TCrn@6KcqId$aFXjl$ z=AG2Dm0iu5LYEVTuE{ATgXf}d&K80>S?F?vRMI0>tkY{Ai^fH+K#3yVD@L-YVGshK zGkfOT>H}x1&scEIYcN&k2X2k3$U$XPZpIc(JjZdLLXzwW8UlF%X?KOq#tef;y0o{! zToGp9qR>+jlzb5`j4Y1yfl!&HFja~%4TYeT2qiinycVm~;hJEuOil(XRqm-htPYX! za9B;Q49FTfX98I+vXJEpb2ce>GU+UMEhZpYED9%smGC`-rfDK#AS?9+NT3-KGH{c{ zGAk|X?#?8q)ksy{ca=KLECw9_mF!u?allE%A~>NK=JbH+Urjjkh^k`G8Y8ODCm0r= z%(U9RwaCs5wn%&r;kCj<$7Tm%n;p9yCX72c)1U3!;$-|5XO6E4J05U4(DbthO@BVR z&GeJG8-8gBmy60j*&wkQxw2C!AE74Yb# z0v^3oz@vMn+~^RwQd1cP@37hvvvH^gWo1?1rExTxU~-Ot8Oq?zWKH4oGAlHY+T!n9;gmgyz5 zb0F@df)3w`0=9H8HQ;17$`{#NB@<}R==6aYsYy8td!xgK@oR ztnXxBkbko89ABB*bA0D{BIo%oXXJ9`RkBV4mnt1hY(2F{IY1L!Yw)@5f^*$PCOQ_T6#}Ny81eMLQfxR8=7!T(7M1_z zX~mF`1vE;W7jl5kL}Kz&fD0nIr9rrWo!keVObHcX&Mt(P$tDe9J-OgH zT<>N*MBJ2dI%*L5pZpUM+^%~@nM&L z9%jMtwUsrLX4k~*;h{(=5DJyD2uo2;Kz*FDI~^ zN(<;pq2fgxSrSVXWknAVcT^mpWIKdXtBW9Yxp2;o;nkEFXxWy^e;TJyb1;L~uj3 z-PPcvR?p%GVza7mgPvzSm9}^IeC9>$(3)_D)|^=ru`_EfWoRka*Ivq`?#{TwAo6GwoTE__qcQU) zMn8_We+^CTW6t`%Sld>T$F8gf%|~ywmOKCo5T2(oQEK&ETvLUH_&E2?$MHQU`#@+c z&ezx%i}1c!@Zi1}*%0|*v$xg}I!9`y@-bg(?UA+Z-=c_-wV}ks$DwQQse{-(b)MA$ zhR^EEtt(sexpmR~`1%(QNV{Vc&rVvEBve>MJv0;a>n^4sQW7u3ndc%}G)({|0bvH|u1*78q zo{Hn=pAUIP8lHIIk}^k6chBg7IeXZZz`6|}mkxy7gNU*ObQ$`@6&^Wp?dll=7x{$q zB6}4*Ag8WKB&V+UD30#QwD>YyMNwrG>$oaY)rmxI;!}5xFy&nqBFC!;m+%X1u&)8T z@&M}6;#iQ65-y~)r`(zrWl{E{?&Ng8+e(3r9gv@PZj_NIo|ZJqC``SwNP&Vn^G zh6`NRU2rR~0nTK7{0IIw+wUhoTPIkE_gg3Kaldoop2lZ-3Fo>%w;=LRB;DclM%SY| zr5+9@;F2lRO;5~9q??;KPh45~I^7ipguU)cn{!sr4^T69x<{Rc-xG9oP-dPrZHI%K`f+e4;x5Twqqimo^VmdcRuDeA;Ll4ARbu2GV3 z`IQv1H77!gtt**+CDV7)>5a!{jNM@UmG^*twLXWjEU=5`Namsi%CEWgWa;h@$cp4A zars3zYy*xBkJv0ChT{nCIxZ%6lU#D2?f7c&? zyZ(~{HDGe!f+b#^J+qxZ{ z@kqyYGt3xROwdy$-wd;5hDa^~dTBt6yO@98qvqO{@;2a7&>4JqgqordngSvtwB1=w zTZ`pBS-k&{sUesIS5=la9R^Lx$ylQkP(QfPI4lSM1(`q!6Cum zkW6q=Lo@h{EF*LZCA__%rx`jOdLb0qFN9|Daad;9M85Bt7`C4w(h4uY4DsB(rei#Q zKF7)_altmuPIsmKXFIYzbPe}qaGvi-*b1_*I;rXG5E#@5JBu1fEU)q;_(}q* zcHQM&Q1{RA!9pkB(0&fnZ201eZI;dcB^D*3f$(lSC`j9@Blx;gMkZc5xyI2lu%Lu5 zNBClNc2mbWCUK{hBN0H1KdE4UU@^mjcQ-XWcr2eojm6lLTBIHLUJFMW_OhfRKJXHD z0xzLF3II0B)MUY1)sMtO&N;Zn33?c~Pr(gbbi)Y88V8&;j?)hN0JQA1;|XsNK5?H%Aswx@zy)-p@>5<<{Mm|gB2w@^2EAE|P#xnRcI6VXsN5)7m z6Vpnwmzb)_K8xgxWswhz+~N~{WM25Vf?tjwOCuBGWd!mjx>JJ}i@TUi3jGWwMX>NC zGNgy03}%K+xYO-<&ih^=nm**lZowLi6E_T6Q3x}lP}Qo!7RWqk8|HE?tgoY6t) zLG}Sy;)DzB7K5&Lhyz{#Wokjthik(b99<>^77o z>y#c2=3VYA+|@&6vXD`m^r|1)kVcGUG3^eFfhsZVP@UkT6LXAkJ@e#3rdJ;R$yi`TV`)F3o2Do9#-OKEA9z`~=HX{VkCL93HL(CoK7eb4Otyzyu zol2U+3SBR)hQzm;uSuXoS3_XXS>?dNdIW1X9OwAXkF&%n;1cIehMzc}`ykVEpQ$wI zFcs#y?SmkU%b@v04;n41B9XL3i=_w&_Mhm*h=L~?@rfRYaHDH5 zQ$2R89Kisp&oL@Mc3H&wL2%gZ85I36C>DAKML$?A$7Jq@E?Vk>v(&Z9C2EURWXb&? z6m5}}PFmGZ3zYrb14%^5ekz+C)=#eus8$*a?Pf^-tP+AS#z`T)2 zT8)qPLgZtl^q|}%wLqd7M{0{8Bd<(^1QjJsH40{=nehSzWr|8SZSqq5rfsNZdNYLS zJ#;;zti0HNi$7=07Pts*@z2MZ3;0RC|0#wk_M$L1&8zaL#@GP$Kt&7j?g=CX4PmdA zTO4q7Zftr8k>H5v*h3ajghaxE?w#8d=yWOY_Rzvf4~z#$SUqG`8gHpox@)Q{*zfbdIJYxa~EOhjg4yMw`YPlW~Z9vTtU9Q!ddRbL@sxZcm$_@IX|RI;Zdg@O&6fM{OH@JSPF)PUEK0wC}`ca00uQxKpfdr_^^j`14Fd{KEohs+lghL&fxR7MT4Fy)Q#&W^FX_Cr&!n6@ zQ{ChvwmWJL<>Wbd9e~hL#~p_5@WqhZI$32@&9LDb=E(mH=J{t}`4uXhZd=YB({kI- z&@CW*o#urgAlOFo9o!f@(CZAWRuIb-e4xlgC+#=5t-4{);QllN2nzBu)gwMVe56J? z03PE2y08f0Smcn{MUG7j%aaEEO3S3C=@Px3Djxd=e6-9uovH@Bx0ud1fL-y(?j%30 z0l-Q7Jp%55I2tfhLFW!lA>K)7z;NeO>>*gJNdS+}1CeT3XD<~$5EF4ANb*<6YvZi< zsG_-NeZ+T1kJx)%fW;&}e4J#@#d}C3%0-U>EdA9(_g4?}*AOK|3;|J)nv~&Koyj+u zJ@5zp_z6C^fGz`1Ad=n}I+SGy3`W&KRflYJSvK91_B=(G`QQrL`j5_$XyiyVawHl# z5{(>*-Z{3yNELda!1@aYXQv$X3#?Qjd>-Eqk??ai7ZXo}1eIx>XXO$*4>~Q;SQBZH zwoxWxS6XdvV{<^@+j>&5F4Yxf;KqOrPe}14Z8XCVDxu6oXFXopJ84I|c>pg-n`d$O zWnogF>pHWy5v%oO>aBP2_!2xY&Y7d${gapFB*|+0QHevW(9fVU8=M2S^L$ZziKCd~ z7DETBXbu=$$5D&;BzKWo$5nq5_n=sKIgNBLsOE2g5^vx$NS1P7SCPA_RNGjNgRwA- zFCVg*Xxm7X@w|}SLanf^;k;RcY3=+5auhyIg&zi+8fDAogwM9+AmjHC7?_e10A+1N zkreo>D1M@iLuDfQLT6|Sq(tYe&;M^Blno^t*^G9x01ItWL{UB7=uhzdX|@&K+16bg zzPqgV5i-WTvhb6KZQg^Ce@f`@A*!?1-f%jY|5>Cn%HAJRO`|sAwCRS<>Gm}m_Vpln z9XtqC^h6bS+}RCJFE@aRKycc?Dq%XFRm!Dv4~_-`1ej$<)v|xbD*hx@{OL0ZeKwsX z!q>M)?74N zDvSrbjk@7aH>AK}2GQ@K6Lz=6ziMTb+{%(k>SkKkvh1}`BHJ=8&>~MF>*<2;!8`M~ z%;h;J)0h_klYLfjm0Q784o{SQW@~k*QCI}JB|<Cj-Sbf=UJ#wTU> zMA@^Uk<@K@#b5Q|Cm`b|pP}^6{tDk;fixa;SVwUrj<7E#H!r~BW;oMuX%Wt5t}30u zoo_Srf-I^NYPw5DngFwyKD)Rkn?H5JI>u&h9t+fUW%^G!Ubr`vEWv;?pJu-1-d2}X zF@#TT(A+@FmSB`EcU$d0V8-mW8Y=*tZdeGmV-><+*lwT9<)%R0BKLo)hH*U{=9oZL z-vmbvLq(1fIwjCB*$1Gc`#=rhNzSj_Uz=hRq^ce%~gl14)$jLku zl+}CQh!G@2%QQ3A@mfzi_)cwyJ$*s!mT3G zBo^xOMh=yTPR^)IccZ5|tUrD5ITh5?M`dwl;Od$>$_?;Q?1Sz9jkW#+M;HvEV`#A* zQgI(tjIq@RW9x;3n~OYWK85XkPMO|NlAvSzndqSDr*Oer(~6A^<29Y?4>o+o2WL zNL3Vbf>*&##N5XXE2FI%2#rq6RmR<5Tm_kDThy5-T$DHywVH3RR!0wwan7;N3;i2( z95M50^=E!efeCWc4{eit_`F}#5PpGqNX*a}Ek6v6*+sxEK&abM1-L1OVyIwLC!%ljT2O9GZVWp;H)a{zs&&4sO1+Fq zkA@Lkzn4B(XVatS@dDSp=<;Y#erU{S(qJ^IG2|Z`i<}>QB^rdjf<)?@mH3cI779nY zT&C-(*^otD12* z#lXpmnHD3ab+LDv7Be#@{u|2x8oCI0`7+p29p2aLvkjt}6Ki|@A=0Rs=#$sH(zR_H zU)L-6iflkZO#^n$S;gPW^s}m5B8$e^1Rv+D`#Qn~ynvn|k1dZVi~u1DBYuvuf2XaV zutD;Jt+zW|Jnuwo;!AW$j+-KPL;|oQ^1J~!A32&g{zgar994NJn5Ce@eva79L;T$l zH)%TVW<*w`eZV*9gveZZ#~ZmYQcPRT9T>u*u4hhbJjW-}ewlc5>i z=*=;YkpkEjMr@33BE z!StiOK$D1eP!ZX7~?I1PFnkv;H{z0gGK~$<5;8m6Q-BsxrP16UV ztHZ#6R)-x53-cI^c7GF7&sa(7wS-DrAf2)q&hK0#MnF7flTUDAx6XvTfs54?~2 zf%5gP;o(zxF>prseBKwFAHEnCAwht}Fb!$;hBh0+8d3Zhsz4(wE};RNj)x$gVLzLPYa$B zEbMYh@HvL>G8dhD0Am!~3x34#qu|Fn{Fv0x+5kb=Q{dL1!$Ft`hlvC}t$=pg2Vzl_ z#^H>L<>Jm9%cVpv<#yNQGA!ll`(mKz*QOfjSkbFikD5b|4YnO>&((SI_ zC>l>4Spv`bUnKChKdxc)z%>lqAj2*0fYUrqIvsF{XO5)-S8<_0 zN=32kYN3-ZT}k1vx#o{Ly22Ub?-*cdhQ1lY>R_zde-R-(!(2oI#a&Tlu?Z>mFC|23 z?~2;@@n+;c)+ZV0fOgl)mQQQa0o#-JLGGx~oH*h#AF7r%2bc^il-cq#t{Xg4xZyhM z2eO>?yXvR;$S&6jS_ubU^xbZzn$MjE%)kzcUD%C0}z* z@Wo;>0S~I=TZXBAtBh|aSn(Cr9Ny%}0je~?ZdLQ?!=a|(!vbyiL@~hXtSS}XLqL1e z{AT-!3^SVrc2TSRkhL4OlPClL!@}!H-|N2IxDced1M*L!k!{H)lK*5DV2buYTem91 z@e{A2{N#ARz4c?qO5WdC$xSAne8GMdgfHkp*70+)J@7f%y@qPmqB0yesB^gC*vmBD zE49R6^Wk{R>t#JLVI8A+_B{60q+ zoyTa1!L8IL8sCS>JI7FHP|O}4=bTP`%Jkon!bl*FvLu3ViJehkXK4FLyRP2=@(n&q z2@}fJB!wxsx3owmKnBO8%r~PI8C5p zQ*E>rP*GoC-$TtkP~Kyo4pogLQ$N}_P@7XskQaxSL8X47eLbAa;5)XqOc=>vS{N+1 zU!rpfM)Cr=>!5|f=J8Mv!$9CTg^zWbAiKqAP(8f%Mfq$Ef2eevJ@_lWuNUKlaS6?_ zsTpU_w&T%yvv?gWCq|seY&H=9{nh~i5BHO@bb+&|+HEx4(Ma#Wi*|NWdME~?0RiWBaX zGlRSL44+Ix|Cs56yA53}b}P>F#!!Dp3*zb+j`+}Jim`ei0GNrLKZb{TLLi2T*AJ_c zD&esp&Z>BTh}T#?1wQyLwLxgL+vgsk_k5nfYSUj(#1rpWmdL8vOsNGQ6O>w7u$dtA zGvWh6pJRT{GLsrIm3xM%A^9Qp{@5kthwKRvdJ1YPH6)k2fm{t02BKylEviCA%%vr} zT>1>P$_(U@{WF1FSmLmSc4*GQT&W?$MA91;GR8~N8xyjPH=VX2PhkJ=vw%bAIFa%M zr4Wp62Hj9W4}}d2nL+7~b<#v95p_r+%YRkUGOHqWh6CpezTRQ~#=YFIAVih&sA9My zlk76nk>xP-_*srwgv@d*cd#W;?Hd&%(|KmXS6z{fag^+aJ8&WgW9Rrvhyn5>Kf~ns z3?~xVzWE-1r<12oM^Xem$&NA^Y*b_HqFuvLF+$57>kwihtD4Hipf@-&97Ra|Xf**C<5&Cmd57bJk$jDaMWl*NGnrUYsr@CFJv1PEZt=2DjLId|@vdq+oJqL*L)`liLveeRig zX68I|X6~+zuhbv}mMuPy$j-z65R1>VFSMOi+J(48gY6sb<+S%v`!W3EP$R?V#c1f~ z#gEZ&(lZ6{-&1vd4`bk%C!9>aGiG8YgB}KxO*f)8JwIqC&h4VJ}^5Kv6 zQeRR~C0tF$c<72sa8|aS%C9WGx)>dIHU4qlK18O@YtQe+9YxsjNbyr@$5Y5mJDd{f z59Wu9D7asQdoJLtwM8GQ%V740MHl1TuitJdotIonCn0gISlQt`jbo?IH`)&uJy}$A z!jL_Py>#*b%V45dr8Z&uZBfzjLpVKqak1Ksy-p+S{-PB$L#!xTRkTGry4E@7nm+aN zIXLvXyvBK>z=tRWCLb1kQG^4u9d5F}Kn=Gb3ttAu*!OKDRe#%}Pvjo701K7{xL%4o zNa_C2lk6Ah?)?*R_x_tS^}dPMtLDB1*P=JrZ-rCwc*kMjX_~6h!2^afdDKhINp9z+5BAo?^faeGmm$n8CkLBF7dTc%3XDA@3TOW&&6zGTN; zQYAm$1w~W4x5L1glDpr*91|iOF~8GZ72}ESAe!A!89aVWmBH#{OH_le>C){)wzUze zy3wv^Fhv>Og`Y_7&dGQfV;_8C1kquusrt7vfsNzqso zDx+=DDtr<>hO_6s&NJQn?gv?5eY9T#u!crwgDSCKB-ew9CCIvD8HsRN;1*mYt;I>` zz^(3*@K$=X1?SeVGUPH)ia>WXDrWy+YlK-G4U}#@sW_uog4-KLRCC*+gWC=0LALF8 zK$hhgtN!*mk{JwqL`wPyUwwyNH!e!xpO>A5AeG@HtXW}%8}9;mdox~AQS>r}5R4PY zF89i&vc?4+*G`r?$KCY{1*lI$WBIf2j#CEs+zbn zlKonMSF(3e$XH(VSNiAWqIZkPo9`lmVDpQj^VLl{*A?GH(f8Lx2V>CDL8}wGRI%!> zuT&Iwy0187KONa0rhgtrDbDNRmKQ%x+mBOmcwL-Z5^h8JoJQ#9ft3_SogVUH0v;dg zqN;TjJx9TqDvYgnsk_ykr!ZJW7t)-3>c!c17rloWSIqF_lcy56*TIhi{tU&TXVh+Y zu2nm6?OCCGjii_221Uoe1xhdf2{erVSMKJUgWR65HUZ%#JE3kn?dovayE>uhLZb#G zv7MlcU8m#E^h1g+FR>44Eb8$3ly=WkMZo_k;&{8!DZ;G}v+aZs=@20-?s_;j4sR^F zyvDVK0zlN1!nmJ^TQB?y2A-YpH7$I;p6~z;sN=bZXML_pVQ~0TTQ(h&S2N3_#PlJIE|wK{#kS z4aZ0*;51(W$a$L1sk#7*uy1M6^)1ZsVYrivpLYWke(MjzIeo!{!cOC@TByNNTB71h zFw{@}kYZn8-$ncHveWpw9`;{B^}T|seUj=JXC(_I6kS4&x`dBjU7slYIN%trCt|od z2e&>6P&T}ovG~svi~g*3YYC{_Cu8?xboBd}+U-aZ;ybr^1syQ209tzau_F#Aweh@*sef8aR+o>PS*Xum)YPU2JTs#E~)1W=qI&46u%&?liwakES* zGN3lN;2HRi{`n4dK*><$vqjJ2zPD0;J)DdutBhqTSCYQOH> zM)ywO3FkJtXVE(EwmI9Pz2zu`_Ld_r?e*Ux=jZ?bzeni-I?UqeX-_@{pCK5=IaWNu zh{p7|k@vT@@O?3BQ?Ok$iO7%k8Ia zdo`Z6u?I>X!Pm}zHz6~@{(Qm(>){^#^hEoyi7O}KeC!45TlUI{FHFR(4R4^Vq4od0 zKF(m?0{ir&^CsCBPU@ay{lH)BVDU?+1CFk(C;agGWp;26%f33W4Ce#!*#XP$DZ0JL zzN08pWDj6HgYQjxKmU#oP}ncx^AoTtzP;GK1J64;AJK%B_cL4kZn6DdaoV;!aZjj) zTUYhZto^Qyd#Ap`t_htJP;KvL&xG42;F&G7bzs8Zv8&JblTNGtalMu6*;#xJ(!z7Y z{PQ8KLUqSwi!ZS8F^OIqAK7>qyzdpSEk;BI_*?q{Y{PV)~m#=R>5&SlYQ)la6xW0Ya`oCP?Ug>Q2Ov+BOdrn_@x`iiw?&Y5!;G1Xm zeH|X2Y?wve1+5TkjfA4KyvfugB?5??w&b0tO;(`MJE$kZD&)s#& ze%JBOZk#}|Zz_GM)V^|h_jLQq+Ut))1xs%)weKmtuQbp0xyRY(9!ExR;R>z&FTAD1 zvagujJK4T>^Vc@VsT5q_x8I%i?lk*@Y3EGGr`^gjWw`Oybn4M-F}JP<#0JuaCDMIrHT+?YGW+|4gVmcyZ9ade*X8 z_Oe;G%(A~e{#%^FIr09J?E6nzagzPeg4Y&U_VOv2DfZu{JU_*LWy)Jq?8l~_zq7rZ zs_@7Gf0}6z&b;)8_KiOrI?%rKkn0Yyzc}TeKe4l|=O*mmo%sj|ax$->%ny-uuHhG_ zT!MFq{lv|UNA7-dt13wUT-$1|MZvflU4Hv+_G=AG8|{l5FK@K$wdKR*dA8qgu;2HL z-rnQmJ?u~SxOz{^esiyP_p(3S>&6PpzG3g)z3sdAes*u1QatFTgX}jB>O2@j;o#nb z?cRegJ;btqd+^^5wqH2-4WN%4@#qouQ%4LQVXr#k^&{-=qaK`NKRWkuoIVe|9)g#S zzVB%J&qqIVv^{wA@X;3keEw+rHD~*SITsycUv$i0jox8?%9nki`mO!&&TYpjypQ^ zb`Nh~bVlzPcJCRh&#oe4L!XJtL zRrIeS=N!0YzqG|yTiEYa|EC(gzr~wd*q?1NyamQ{^#|4VQ1xd(zuW1%o$ywWOQu-% zH+y`uhkfpz7r|36Pk(i~y?Xj5Q2Mn8KXI`A_d{Ph)UuzN_0%l;@3a0f%YJoMc9ylB zpL4<_d&5ob$y?bw>|*cUjt6a)2dwG713i1vB)b$tWYR|Vwm-DH@l9sL{g(oE7N1GB z?5RI=wk-SZ;{IYRE$>E<$>Nzw1fAhxtT8XNaYFuffPJ_Gf=}7LxSstgZkR*Z!}n`( zX7~XF?#Cy+Jqh2Fy?6uXL!tHnK4ORuWInf{-GvuO+C%t;AwH1#pHj>IcEfWvvX^f3 z;6^xMgv;0VXB+=w6I@~L*#yPoJB0Y2>M(w;p8WY_dl+AzbG{~M4{g=8HR$l+Is3e_ z&N6&)?v^t9S7rSO00a2U96mDFy%p}l!DqSczU>FLhbg|wZJ)PY=XUro_jTLZH{k2s z7GC2tJk{>p<+5EYySx04<@Td^XOm_BX}7m_v)AnQ!EQK~+WofO?Y`Z!yCYid@uxlP zKkqTH2i{Fq@lb{Rw~BlAwtu(xz~1)K%C1T~vu}DoduV!khW)^d%nW;YM%Vs$uN=On zWnZ>88)oojE_|1Z4VBI3mH(+k)Vy*(d)a>HO|vhY_T)4>J)>&|ZbI4T<9+P(zE|vv z4_jsSwFjmT!T%n(%GrLmYPiaN?0}aKuwOf%bEe%rb7-dB^}|arx|SaD`62f5qn->(`G*~+wPyeVm8Kk&FUKaoTG2R zz#Xo-`vALhX7@~M8^5xSJkmZUWp^yGe|k>9?x%@$H~(&Wr-wbT-YSUU=AxU6@G6Ag zV5&WTyYsiRFGI&${__#`KkiS z=R6la(2esVbQh&H;5VIjO#m0oXrfOSU0;Oz^KSw1OGR%KIhTLzJ8^2%xd4Ra1s>sW zF4I63_LnxU=A7$H+4|=T>%FiZD)-HLxY)9EBA#8kXrkSXYaf>V;d-B~=UnBmpPTs7 zL|o@c1N;@PQ`-Z$N^Ri|m29c~PU-EN+IQnN6uO7%naTD_+(?CRz2yg6+MnQkWSFpV z3!!}(ZjrOE#r=D@9q*Phb4}BW$2;()sKI~<4;A&$a_cX}CftPsL;D6C`k*`3JykTs znxn`T!GGU=XIYJbx@0Qa5v`~*%R0y13|K*2hBEi@*3I}qD}Tqv0q@4&o;C|7rtn{Y zUZLe>rK3tpFW|qvF>JnpO=b+6ovG+CY^q_?HHJ+XHXEX-_3$6n+p-n_NvB3{#W}DE zk708iY_iGG%lR{Gdd4W{RoGPGKd+zP$5!7cxuWrfG$~nhc%|AENj5GdBLznQjuipGi{@CScSm`O#m}Tdobovf@A`{z{vFxi*s>8~+(LucRXC z7^F?`Uvc07Y;Emq`~Ph0+HC6B>>!DNZ{^x-=GZ)mI?J>hY`WUP^^})*MnjowKpQFsYwXv*|u)msZELN||MeNjG zGwZsjmwcks%XRYpW%ZI~m3m2gW@7b{W>HDhhvU0xN4=UErB}Jfu0S@m28cArB5lz& z-y)zPk&MMt4OXq&8~H}1Yhqo=Hdb3)Vee{$YSx0Seb6W`{wx79Y#_e?aw9s&v$+;X z5x#NaA-4hf+CY8_q;~_q%|k#Q!w~Rt{RPND7=Rw~0+8Q9L>}@wkQorFhkO9!6$AMa z$R`+p%7(R}`iFcGgFx>z9I-Cis76kujj5)DRJn<0P%#3q*Yn!~ zxfa)bJ!Cf^zcr9qK!(sAsueU+yiVgLoeG=5F>KmklNrP2QrJ+Ua#i^30dg#YqNxPc zQtJ7$QK7w^Jp4y0p$WTaR`3$facMMVtSEttb*>T)^a^l)u@Zu?QA!{iisoKoCG??D zst?chcKUvi5`tJaDjOM}Ig$(_k5amm|mar14ams>vET0lMlAOynI+FZT zBUG)2(DOUupwiRElR&;RkXL~GY6ri~2SC=}$&Y*mq19Kx#lG`BT{8e3DXH|)*`)wvorYxndcKL)ZAL(^-;d?43XFv77#^%!az z*bR~BaVktFR#X~@qfB@^H%Uc}99!zOqB6O~=vC9HT2W*}vzeDzQI(L2QVWh-^CVJK z?Kl**9k^UYwa1!MvA8EFtF5gr5^um!2?p6nielB>$2Jyg>i`PFPLhjKj&WcA^UP|1l! z_12st86lgOVDq4XtO0VzQGT0$0lDBue&kyqe>RW}CR)}XkM`Sa0c6`beq?VT^DuTC zpAxxsD3Bg_(NUd){20h5C;D^6fXtoZ&-GIvS&TX_*F``UhyA&32l7C@A6W@xl~K-W zAQt}f%J~I#r|AzAW#345$gH6NXq)~XMUtU+H9S+ zlo4wDMaWfrz8|?7$XNz*6Od0e;*^Y5e%0yEbq8!(F7zY!0l7val&e0Lv^KuPZ?gh6 z{csIj>v+hro&%E6h{M&ISbXM<{#1*Ol8m$i z=!qW~@s=ZP1_E<@5hyYCQ)#@4n+h8uz}rnojz;3Sdt2Ec&fg2Q9P82wM3~jj-o?ukBv5W@Aq%jtHl<_)eAJj z&W{&Kzm z@~VqaKcWvOSyuF0ZUrGb0XY1V1tt$bswmkp>_)Pf`fZoVe#eR3DPR z{;-W@y+eiR#2O2uPSoyv{mdHEJr-D_^YahZSQ@@p8XMqU`d`-AsjyKR%U~a-H(%n} zd}s=5>>@H1i8R(X4vo>uLCxk3k%g_vSSlK-i=|?Q#`-3^eJDl_W_oonYJJK!dZs>d zbAQh-M9*LDB1%6O0r|@o>!L~Dvd)V(JEl%6l`|P(e+@bHA%C5*71nD+sFU;;9f3m{zQiLp z2xlpO`F6TLdE~Cr{;C&7?614EzvjXQ2hYC5BR8`L`)f~ftw=O-OBb;XjB^qn*W9!bR(>T5+jJA@BZJ(ka3JaTVk8$COG=^^e}qnQV}|n%y07qklq?U@*0rD7%TJtz$QJ0P1%O1!WcID!{)p>e)gk*ylfyL zASe8oZCG`xS4njr;56U8PM`1}R$X=+^Tl{ncOYa5QGu(QDfGXrI+89)sW>ollo-OX z6@`c5Kqm=ZBvM`VI8=9+R$XH(6~c+gXk!x6Yo!AD9AoW?s>kxFj_l&-)$3gwrJtVy znR7~RKdW-6&d;OHyHZx2zVCh}2G!4dY7YLv{oJMdc`A0n!M?61RuT6jI{`WKTt9LMko_<9BgX)le3>6P z9f%%ZPJNnzd~4V&1ae-NKi367{(iL|=>c-xHGbr7vbo-mJPc&(Wq#yYAd3v-Eg)N9 zV0dfMe*<~$9zU`k))QGwKBRXwO;08SvCKn)Ko;G{x#*av5x&3e0fnfMG7UBt<0c~F z@>Z})2{clc%*QozW$N?{dfYv=ta~g#=a!Fi_o{#7JQy_g(+1Cj7LIPzNSO_dnu$ls z{d%NeS!f+@81YD{-JeHFH%Uz-8Yw;F7%B8}NwtD)j>V&)WHeGAP3D~I?sI!AUqs@O z@+sRmHJOcmKJroSXM#=ya?1)o(gNiA$Nk88K&o)#fbtIIx)MmWF`8}$(u1)pTXsUlmKkwpj z<0iwetRG!x+(n+7SUHSSU;!v z_If`_KZE1YPYE2M^h5Uyn30wcDzWEdx5td0QC!@I%7*%I4t7ury~KUk$9~UOj(a7& zhdr3j#=Vl>tNRcI<|OXJa@dfkiUVY$ROC0M{;@i^5BKoza(?qVlWtd3{X_8NP5p*^ zzIVv&pM2wsXRG~&R38@WW5$IV;qwwtYJ^z!hE{cNIJAcV>E-@$kU2o^HjvYR^chGT zNWX#n97x7Mt^o45f&2@IUUG0U-^-RK#u>~k6Z-gXW#mfTY$9S)*-K)hk)Q~ zWIp5{KwezWkE{W5(L_dYe@QZi|56(-vN3*{oqJadoYiJy95{6(MYKr$4EI^kCa4PsIIl8 zB@(aac*3I~>-Jc_k;0>3$|kB;)tKE4{oLRps(L>JlHo{V(K;c4dvM;Koa+n4MZWkE zB)cayMJM)!F2^~(pu1SS#8Ev6K1cJ0Hp-+xll)Ra$$>*9AhpR4?S6;tSc+3z*l?@O@{Rq`eFd)J}t_g`a8 zEEA2vu5tMNdhPc%TqtSwdEN7SW`^6(qxijef7eF){eLvV=ge=`2-WvL@Wo>WG6C0y zbw4{z+8l@;O%5^z$W-L?=9K+`>|!8C11UFA zJjQvOAH$}044X4xQ$2>w`LKELM}GFJfb5DOuI5U0wW~F;U=AbHtG}X>4PX48kj?!b z8~~Eh2#-poIvQ~ccDL{Xc`A*Q9F-I&%_K)9-F0Oqj>dGPpho4$Gvm{GRIWlHIBnre zJSwY?ep%nePL+5(^J+)ieyGCF)0tCtFr)gCF?; zkgYKBc)6wkX)}-tAlIJZx0wax9}E1*u|Qhd7-9XW{vrKbGX?huQ^j>+{UpW_)w8Tj zLxHL&*3TToV5OgjH3$FTsD2wXMgkn|ezvY!*3V!bHZ_|MjYB^Zuq05&AgRcFT3RKV zqbc`nH_zsSOI45M)sHKVADrjfIE^_4{j7V#K^6eP15LhYyckH2ft*jdaGlVL*xf)Z zTYrl_xWDLZD_p%1E84wG{DPFFf zfs`7^Od#b3@?#*C2GRhe+Ca_*QfnYr5n{Bf7f9H!Sq>y^Ab$t4@hf3Nf-LqO`T^&{(TiC#7Od3zw+FZ0{% z0pyO`{K#w|wRiZDlYv}_;Oj-C1dv}n>PLPKr0p+$Oxf5G_CTC|aiZ(@CjGM~6JNI5vJ)bX% zHn?~9-N!b17XCsbJPRLyhj>VJxaY*ZhIolasDk&xJ7Hs_JW4*r%E}vGelE z%dLO9t`$kZF$Zc!<$YVg#My_Xo zd}i3Z59F)&RW9YwFMw1+AT*QbKB>em-wG>>;21VlusQx?e|?Sya_J|286ACN&081*;i08<+TzG>`|^XM`25JVjXjP+m@~@GRCP)P{UsW`%3-1e!Rz z{+AWLRxA8zy^nve!Y9KoAMZ;+j6 zsgC?TK~`Nwj4rKB-G2x%h$aE#QpoiF4RVlarC16YHZ#_2t`V2Lsv!2Yg1t|$mk9Rf z1$%Wt>}v!&J@sR>bQ&##4P?f{g1x37_O}Ilk6@>#nN0S(1$%8l>{-FyE!c+yd$(Yp zR}lLvg1t+yuMzA&7wqAJ*jEYmPQjiP>~X=~R1o{~f;}zR>3%KK@23j(L_zF>g1tkq z(@OwM_8P(7Q4ssnf}QTiGPtG<2=)q(-F?r%EqXR@h%AVjF|#Qiac(pA%4tY7wZ|9W zJfp|uMy)ir!k8&kc_NDDv*GKW99Q$%sJOasEsAwo8o&hP%&dxs{<^VOwtc#<&TiY6 zkJ5IY2mg!hnpVaU(s?t3*Ct=Prf0b4N4DAjGuDQ4%{Ql1=6;@D$@O7m zTBlIm0Nms%(`D~uwX73+w_q<9>}kP%zsK(S{pnHs&YJhiVa@xv+*WjPEAnZT@3$Gp z8mTAft|ju7<7&PfZX8SVUY&Ub;;XaU_LoL!J8S;G*sf_^?5~maJiUs&JhILHJ*P^+ETjg4bTv`eGsRYj#e?tMJ058e7YI2b!ufui8`R?0s?k$@9Nu-O$QLQFY{-h@E!KcI6exSKa; zuiB(zhrUsc9mtB_giwoeO7RDWSkHxv84FUYYa?;(*z{u49e$M_@&RnbW7i%gJxVeHl$?FbLkSa8*p)84|6BBxSwakPHDcr zxtU&enld|qM@olG9c>r?m4n++T4 zxsmR#BcEP?(-kTno&&9#F@fqtKK+&UDfvPs@@WrXu()gkyO>cZr?af3! zZNz`dr#G5A-7WHI^(a0iGm3R|ce;vovOethd9YJ{r^iuSTI==GDc<->j3d^qn@>TS zCy_5oFqJ4@`~nuTf5;cFYhR2!z6OzdtnqaOT&;XD^7xv7DvUM05~KKn`?*W^bE>(m zt=)g4lhYHgZH@JdyWYq*r;yQyu<0?@Bwqs=O!DY9R~MweP^hCm6v3>A-?X<_A*k;> zjo^p%16(Ps+>BQ{JeEDbKL#7q7wa;X2ZJ0}NsVUWvHZLq%OkIC=xQk`2XDc`Uvq6! zaoF*5r_P%*yBd3(mO5)u3;qA9)s8sb zWZIf%-BRt0I4XxqHq*L{uWXRV7fACY^6AM3jU87%gD{j&EAo_LS>&%E>N-|jy#}fo zE3RIPZW}AE4vyjr?&pl|=ek%N&qe#+#L02&`|9VRAosKE9yLx6JB4&H`dB_}7Udq@ z=BQK3$F`Y8k#eMRh=ct8miGHu@Elp2iN-QLrLX)RF?YIKvHz&o63iWMCr`t$Qm+(FWz9_)Kr*Qt_E)XtO@7 zpKoBN;xi`dP(xy$O7DONo5?7Sd8&Wlu88vVj%#9R8+|mY5b_SXCMSJwigM2g+2~TG z7BnX(v0AFfp_Z!-Wwl(3Qp_2RiY2wsl_M1;_R3*Wo1_GK8epv1oZkMTltA8*iXtUk z2b-~?1it?__DqdBDJ4i{vJy5$6_gU_rI(9B^yVIVuL8A-XOLP)3FK4NR{!6^d@B7# zWm3f6<1qHc6+mSFkS`w4zHqAPua5JZe38+<2m+H8r=!szX8f^c>Y1=nzUUJ?1kkAL z8pRjf&j;&%PP9ea>s$9qM)8^=Z`AFu4USXX5tpx@iK_xO8MYz7nhnI>(VdqqgngW> zsB0_H2-(!argC#Wx*_BYAeLd%4x|(-WON+7O!3LyCq(B@rGmY3E= zExLvQ(y*EMo{DS}*ZC)2gyy=YZaX|J0m9XPM>sOj2(atr;zn(3^NqMd>)j3V;2N;30q%eu`Fj z8eC*;COURF2@c*Aa53GElP6I`dS8!%<3&GH78(Vav)C7V1 z<&knaYN{eqds{T=E@r%eVm${Pc9o4hHxc=Jq~{%ZToCdlkU`F+BbzFR>N5v6sGKjY zi&iyPzT;eXwyM%PB+r_Ob(qjPq}8q2Ka_)XSn?Cr;pgz2^eO4^A#kB6v}?1x{vsXj z2%jn)CaGwVNQb3h7)^(yv6n!kqUdi?hPkezLPnEx8(~;^(fO9UbRWSsMfv+0+baeUv$C|$`>*9+_?F*W}%*1oSY;+EJAn!RM zKKFG7x4j&eW_;#x+6iY-?~Zm1a^C6e_cy@0y;&h_k>Bx68`tkYgLh@3aeAd5ry=Qd zWFc*YwKgh&$f8IaE3`H)K{@i6h~|P2vZ}cN70Z)IKX+>V(0emvBK_2kq94jZ$0>B* zF|pvS?D%WenKkxDtudUyOEvi~e^D{k&d^xT)@m-uHR2$0fk z{A;A20jV);E(ek}Z0@C8+j1^m|ET&7l%C1& zW@4>grL{^na_*rR)evW`J_o_iG7G{MX>~Cs3lxQR;o-GBiM0AJXd+O)xIQp4xDIBYx zm%>2x^TS@p_0k2d;7 z8G{_3&xS8leBRT?qJDCGrZ>9KNLOE+!C^{HqOp7ht_7&Eyb=m{D#t>_=PIo+JffH< zQG9*`g{b&Ej4hc+hZGFQiqB8NOvPte7b=xv!Vk4pk46`m>pHTb^+qdds@5BG2@;87 zcy%f3d5zdl0O`5(r%ts;jp13;0!6`wVmOTuFKKP;$nkk!Z>Rg~d((z{-%hRO5>)!W z({L-cwbJOQujoPWGGBx24Th`P>BZEnXH z)VcI=x7YTG@P#Qw+0S$=Y$l!u2gfl6d-WJJ=WQyH&m$$yVErIG-Z1)8JgT)ZkaPoi=90J5radRiU}HD6T1ZnSYqWAOZ~ zc)q}^P;=HTR4|P%dTWQ8FJ8#YMfypMq94lSTo=ZnzZze(UNu7yYphmlOr34!vpZA< zkHIiLfJPlN+8U`^&)wt^GmS?Zl!N?r;+5<#T9Z(uHWT^lYxJS=SB1IL-J+No*1iY= zm2M?pJhnCaV&pZ_H`*7!%gaT+=o!Tq+|TixeqP9rKDwpigQk}1=lo+?`eGJxqLIGD zkCu1 zzgo|$=j0m~q~|{TH=3U5*c`8?b=Q86VoN4x-a&oPeE8ytY3i40M{B>w&|(^$>fU&B zKW)*txD^9Xjf)-fj#C;J-K#$f^{p%W$8&`MzT2o|tge@dbI!OsvEEwGJK6nnu_njcxoQYmB~+YW5FhAdS&i zv6ROCF3KQ)G*%ztn7KNy4QVWk|3=do>F1bQ*3Z2t2Pc(s5@}-vjxUrp0(rcl*1eVE z&;}K+)-5B)%zp@N@OuJO#j2r=p>b$K*^oB&LPoRN-*=3v(%Q(g?se}E&x}JG%U)(} z&|QW!s?9{&SQun&JYnv1w@4dDg;^Vod2L7=rSR)m+W1y$;}VpUe?EN-YZ9f6k>}I! zIJ7ZOYoi)mIb+#uuOnwvAjeM?ck4QuvA; z@!oW&eE#!&E1b>@sOU$L)=V7zp4JLK5C*1tc@_?0fk(ZL?>C{l^g>7%ND=b6S9ugn zLc8RZ7#al!VULQCUn(c+64VbG1$|*21rzqpceap5LG>7;fM(&jXgC5O>I}!_Nfbpd zI*y|#-8)Zf2s6u21Dd*mratxmi3XzE8lW5btt z7T(nyO%49R?4(S)-Qm2?_H&#(?h0CShlrH?cfLT$euR;J6OR{w8jA(m;a z=8499ha`{6JYVKzJ(r*yxCC_`c{YFbTh{8xXCbET%vv4gEW~B3)hm3S@_v$5X}vjC z#O`Qj9X^W8m`ZaJX{;X?dX&a)&)KUsX{DDLhsJ7A8FUf)ry74b=BYARW5=2rOLX`} z2GdfgrEBTf8cXnzuT%Wi$dySd9p$@+$~lA9TB7b{{m8seD zJrC=?uV6gq$8H;kGBe{)=HziG^I1H&OmV0=SdVr_s8r&^G0!CXVfRZdP4{fO1*dHDMhVChsL4a zF0I}gl#^e*aZkPNEjh|1@*hD_wdakjUY@Cy4YjKi?aHsQE>?IRPpr$iox8Qh@9;unNO+kasi#~w_>psf^xUEl?|V0@56NGbAfoMS`4h)*-G~3j82-2(U&DSH=Qpn$ z=v)D0g!*Lgx6;|ie|ROF)p7n}==mqSTmMTd;gfL6RE@#S_JR6Mk-?J2VCQZ;1|KF$ zktl|LcLm4rqMiK5DQrw*ke2t5H0n(C6;u|*@b`2KKR_B#F4SPN1dr3>c2=y|;Y+j< z-U4N*ahmq+@qW@cU8~3GDS2ZHjnmryMSYQNv~e0n2f`h&8AgtvM}l8GPU-1GbzE8B z5^M9_D(+fej%kXCeQe|8>jP5xTh=N;4*>~lgl7j;GSx7SUPTxC605iG zdzu{{Mz<3~zB7TW-nHm1bd_sEnlKY7v*|!q=7}ioDANF2q|Difa~tD#aR8sJ%9BW$ zfd^QbS#qREq|8b%jHS$-u+&$p3kqQ}kuvM9W@X~h<~&#ENSO#@W6mH)U@@g;kb5K% z5K?A(9Lk)BLX~?k(J3BQ#Ry_POScq^D$u* zxMxcL&l+=&tr7|FfI+?a#Guk&4O^>qIPxlGTi7TaI^H)6!WQZ9ky)(6URY;@4e9XT zd$SJL=8amU!#Da_hmTIp7yU?w;c@72me%23qAmoG4pZH%!+TNZ{3{uHasfNhha<0K zKG!;YFE1DAux}hX4CBnd(qSLf&?t*_xCz>&B4lF}&%Wdy##sYFM93#b)*%)80&Hr> zab8Q6Lv3$H;~`gH`rfq4&$VF;s(3iE4(Y1>SUQZJz&cz3vCj9^Sp6g&uHKh*c!=4_ zt~Kef2j{-v4z&GMn)pQ`9nzb!#)^k=t;3x}83d3Hcg6vfT2W6xKU0ZjqIlRl4jsOR z8#z=w{M;w z^KwnJqdwM%^H^u1*Rca{ZFTP&Qss~@O3(sQiI-T189gs|VJEuLm)7N|ZCkCwpsxh= zljr4WT8E@n^XQmYmAVyy!$dg*P|Vyl%vwDGy?LmxBdt!I&RV^7#JT&YAFx*GIU<=z ztC=yhN;=&AKGq>02byKkYVbK+s~$^ZrD@lLfl)l`pvkD6anli_UTE!7I{C(UqJ*R<*y)ih$=a= z%*sEozYc+o`YqR*%z>S0MFzoI1Vj>lyWve7a8y`}AXU^8Uhxe0qxZX|Hq^ za?m*a=f8NImP=>BhWuWw{ay*g>>nbga|K=S1x22bj?HN-Z~8~p#>dEk3^|FkF*V5A zcqC`9+9YlCq({~US<(GkSv^iWftYn>{Vdn|$s72s-Jzc_UYzQj`^wvc;DSvpCLo%h z(I})@l*>Sl1ycR8TaIHB2GZpsMOH&H8g0fWHZ3Dp3vB2iC$HqiR5I((Dd$`u=~sB( zA?Pw7Lk4mKkiJ*_Hn#&wyyi!K2W0SdMiSGpY)8rhRqTn%>CPR<;WOQyclQ4Y`)l9e zTm(G}B>biySp}reK;8n<^|s&ULm)k?{m7S;>m5dToGM?C#*!Eq5VtSs`IP%7=UIC) z<(R446`=1Inu+h3Y|`Vj&osam&!-7JPJ4mwZrJe(P4`$}UcfMLH)t#e@tFl${uc-S zh)cyuVMk-RXeP(!d!cTbXe@vCC6DEUQ8PJL(pXN6V=O;}aiPZY(~<}Xjb#g$&(zVx zgQ&V(bI`o}NARH{Xcrbac@mBHH-bFg^Y;&p_rbKQx=~hoO`uToGOgZmh~i5;-rv;Y zy)Ey6FUDxgvg(8vRDm18X7F8BCSh9vNv!cBI|IoW$TT38@39T*S#eSS^cRU0zB}*G z7n`sXHj3Z>m-U?CxRKAsJ@PHXVI~Fm(ar>xLG$Q5*vLCNh?lhb5*~3?TCIVSY6&(H zY4yH?S*thZsgas@4q89p9{JK!F~j)Scd`RfP-@q=@18qW3CSmfQQh0 zv>lUFov#^2l;nE#MAD#xLXPE=KCqY?$ssP+=asO_~j z7S*-oXv0OU!EtCq*^oAN_DI}c-?ujAj6)mYacJW@+yJd&%cal;X~;~ZjpwRa8{{vU zNE=UTZH#;@L(`+9(tz{@l}fSYV7Ob&aW??TuZwR~YK@a9jb6}Hh<2Xib@(f9l99vX5q@N888!A)k$1KOOaqp8E&)ify z4*fKbLqEG-%li2gRgmi+($C4WSU>25Jc;5)BfY~9V;_%~{hUmH)4LmT07XybrEjvFIuV0no~04 z&_)@Sx?{~LXK8Jy`%>_Fv<3c4i&w($!7;RPBW$|ZMn?&ii&}vu=dO0#6>OJQ0@agr zBm7Hk^veNfadxIh3Qs8-bkN&L+(= z!A*Dta$Put$Hu+mZrM0=IO8_f;qFk0 z^eO2uIGc4C9Z`pW&^n}*o;0HwEi;A=Nn@Y>oi%nV%As|bnMh+Zcjc&ck|csTX)O42 z_yNC1J4zbV8moaNGWil~>>;hO2)za?);d4b&>pYDT_!3WGX=fIO2|_iUdbpMst=8I z(~z~%r?o*o&9UJ-e#dc?ofwBU?$_EF`6wxT7i;5mh}k@fq}G!*&O4m7fkT))iDJ}i zS{pQwWFl=0jYAvPtYmF0LLtbIlSms~<*bcWIeXP6X`^-=+9<=dKN=0ifol9k^L>f6 z@w(Q=B50$vWxjtpgZ*h!u!`fjVY<^P&CO+HSU(PW269`EjMmRoSfC?v63ubTf5ZCu_XNDJD91wS=Y%6zKlJS) znMglYDbH~$Oh>rpq@N&$%xFhaG{@bDYK}F>ZS)*#Y&&qt_(NxMUPM{yjG{a`q$-gP zn|5Oz;uKS!L^@25Lx=Pp9HqlGC?&`5?h|Scpc-n`-7+6KT$Fn+VQLDpe(26$d1~Y4 zvcey+>Zro!AlE8Z3jx+uKn4w)8-YBpZBP!KG_ta|uoAF>?x?w!a%mfmhpIlL=c?k| zelASU(ic2e_GmpCxNHfxN?Kt%Oz&P~0`wOh+9Z>4VqRyn})!3u-46)@&q~|knVF6u) zI_H1mDCxOx9D1fFX_cOFi9hFT25X~wi1Y(4y=u~tO&_&oJw>@+K(-P6Xio6HfLw|` zG>~ac7}EwaqZ5^J5%&(9nu6F%1bdlaPYCuN!CqSs`-Xy@;-S&fY4jF71DWxA!9K4b z_EN!KF4)t8{b|7-E{J`yV6PPHor3+9?}@!kuvZCodLyFQ^J@fqQ$cOtR?MNz z*MfbpAoh8Jy_Y{yHwpGtg1u6(zarR&3u12;>{-E1$Ia%5dq=QactOOvA4w$y`x?Ps zE!c+ydr3j;DZxG@*lPs)*MhyYAodQyJ}lU41$zk&jm7N-GaSJuy+aedci)g zAogW~y;`t$3wF8-#q9ZTLF_$(y+*M22=_3fPYd?`g4mxH>^*{gSg`*?uxAQl9~A7pf}L)Ea5bi`r_6Xwun!c( z{=8uC6YTV~gvtJnU>_`qeU)JE7wn~i{UgD?sv!1P1barX(>L$Twtpemvjwqd1^a+t z4+{2g1^b$U*xwfHgMz(Wu$SP%s2S^q3SwU)*jEYmO2J+#*oO;ZUn|(Ng1t(xZ!OsA zp~iJTejgI-YXp0>V4o`3OA2EDOt23L_8P%nA=pa`VjmXl!-Bn5uvZE8vVz#Z7VLD} zlrg%e%@gd03ie<@>=te}HMpji2==gGr{^Zj5m#OiyDivD1$&cVr~7G5_R50TO9XqF zU{4742Ekrc5c`ILJt){a1UucQXSTh%AofzhUM|?vf_;f#uPKOqvS60Rzd^qbZv*zXtY9R;!PDcHk;y073>+oUMAS9 z1ben1_OM_d5bQz0eyCtyQxJQ-U>_9h^tK*Tb#ny!P(kcXf_;@>r+2iP>?aBK;eyzk z1$$PoR|)p{g5CPGkmL7+U|%EHs|9`j9GM!{ZL5PPR! zFB9wu!G5R5?mi3in0^+fA+jK9KFrV*kF*ffr0YKO2vCsONxW+x4>*|Gjoi z>tKI5Px1R2g`aM_rU%)}BirnMF>50LrE#^|1Ic}j45ex6o~Tjv=~ z;{N#>?$vc-Un|&$Q5mB?(`p6#Ji%UD5c?XzPS0SP>@|Y@P{BU0AojNf`x?PsE!gQB z2W}1BaT+d&JuBF=g1t(xZzkBA3Sxgnu&)yAm4dxUuqO&)UnSTF1$((*AHswGX3uvN z#QwZs9}w(8!TzRTPZz{KDA+TCy-ct_DcCy;Vt-n&_Y3w?!M;MUcNN4wAlUl^dx>Db zO|W+t#QwNor*F36|CsN1j&HG;jTAoh%4?-A_7n4yjO%s5-H_ZGzduwd^N>_dXR zL9q7~#NIF1y9E0h!9G{8_ZP%|zhLha>{-EHCD=0svG)n~v|wK)*n@(7pdj|U1$&2J z9~A6Gf_<@|YDN3eGZcI&f3 z&YW}!_G-b7S8(ODeTiT%DTw`I!CocUy99f)U@t9*y;HDP3ieLHK3A}p6~w+&u$K$= zv|yhp*n_A*sBG5pI{Fc#2yyxS;1Z<*n0$fQ$g&f3iefky;87u3HC%m z?DGUWy3K1Z^*{g7_*r%3TAwbYXL6e z9?SF=#D1V)?-uMsg8faw-d7NNm0<4@>}v%3O2OV=5c@R2-YM9#f;}VHGX=3%3ih;M zUnSV@7wiKCvF|C^I|TcnV82GN4;I8;F4z--eL%2x2=-M4u}>B3O@cim*u#Q7TM&Ct zu!jYEzhFOJu&*hIeOtjkPq6n1_L+ixs37(-!Couadj>YxAz+-o>fd2x=)FWL1=d1r-Iehis$K|dQD!CO{(d4G@ z`|3ZH@2pZrx%%(bSzkBz`p0eiL!-2v&*lCX+choBS930=gq;q~9qcs&QFN2XYoYI_jx%VpI2_rKXc#QJw# zADr(EprhzOJtw^mn=J0tr@h4i+{&IOeFU4yu%W%h0WA4&_Bc0v1Dg)5XNu~Qi{2HS z{kh7W@BRE0$+l#jTQF|^1WPE?Q5RaG-W*J27Fmh*R9#afX;nG*_wu`@Cr!m0*GtvP z6VngUc0lI2D`AD~4us!8SY+W#XLX6imZhG^;BuzHrr(`mRjw0(l%A{VtdJCtGN)wD zbuo}tMy{KH(6J2VP`Q2sgl8FrJPxGFeMVIwgFtxJQ^;B%)$a8;g{;4`(>!0vWk5RJ zo>w-z65`IV3Yi8Z*zRw|96}76C=ko2PYMXX^-h(O2GZ+}CWZWx$}#%+ZXo=&I%V?* zAbjtNLS6uJKSYF1bNlBlAbiJfk<}h=jHV!kpwo8l=TBfmcS=$mQ{`;53%(g-)Ol+l zJ#E}lcsZI(wkFlHCtS{fu&LEHD9kzzh&pOxn={BpmmH#x*1%4^OOS0A!6tzxf2l4- zR;Xn`eJlwj;B^wDeO1Fw*zo+WkYzy9hEMMW!q;w!td?j?OY6d@RbwdpaoF$`c~wpp z2qjd~<@y*%rQx08T`?-rU0#n(1u|r`{V*W?My^wVB(zU42Ae|>lnfp<28lHW8@|e^ z>T?#54xNi^I)RiLV`mwVc@zEh=>rlrdgBQowa5)K>eaevM=XW1oL&vOEzQEFRC@39@XWT>B*bEcjj{6*Y-&+yuRb3D@p_{H0>Y56)Z2A}ZY%x+o2*g8jdq8^jdHdI zLeIW=KCK``_bLjtW&sHsBkp7%gGM=xK!QfDB#;c+<<4(niTo0Lg0hgcC!d7NeZ!VUxj8iRyW($7&$`ll*o56bPUB zSNW&xg`EnpZqsNW~Qn{nQpBsVH=xCE_ZEjr@O2GU|k9E1?l;`whs|rAG=OeL&{v zHA(2O9fAblGceF%i#MX72S*weCjWv-AdfMhXtXiFhefOHsM z-kWT+cQ7-e)0(YHtrn{Dfv`zy8$yl(LJ9J4Oa31q)sUr9rc+LPGd|!%vmSf!OxW;q z3aUOA0|^=>Ur#p1?C=PXKJ71JeG15+p_Z3{tTM`ZABY)^i}r#t4VzLR1BSw<07)1n z?+;{E(BIPIfb{86K=nBlNUaf{TY+Saa+U(=GSqtmkRIJ*RL(;{27}BMYimnH>Y`Se zp{VC!lRlG2N<%|)ds`DqHvIKEY`Tq-hk+yvzfY_HqBVACG@76q1hv9xYdhG~;$H+M z*UNhY=`nP87!bamqI?`92B-X8)PG-mUofz%kI;3OdCh-(ItF-krU$Y+z4XH?s7 zARApDv@2QHl(beE?dm5R_ei|Rs&iv+li{6}u<0~L_v=8yjXYAQ@7@DaW!QWHWR0P^ z3Hv~+hL^ViGGORuS0MDJP-=l{MHP@VK9_^W0zoTcbu9@isB0KWwKh-<=4phsjzF$* zqdq4988Uh`0wk+F7)rDz=$lIX7Hh@c3L7tGHYAdrG+Fv0$2NG|!dW;db3N~R~GPQIykX}QX-vH^>HYYTz z0Mu#3jScrjq}4hMx!;e?2DzW9*pT>;U}Zv3$&rWJzsRI(9mmXM7eam0EV+2F&G zUJY*sVydnWNJiJ$VaJKBL8I+|giW>4t1kg*GL-oqA%@?-0FuV4(qp%#V;0t}NJdqF zZZfzwhE0_&In)+S(U-z4-9OZ>9bnU8w0#DUasxRANS{&XI1ozes1_|vwPG-@G1$+6 z&5+TDzocA7IrjkRG2+h?Kt9v+4spB*q{N5-LqNj1U1SrOfpUx<+Zaf-&J}BmG$)!O zR*6$X*4S3CNgJbbS0H7&9LIwQ&>5p$(_qt;;_=mhuE)W;mC>V#>T?2YNN(Oye*=|l z^v3x>Y7C?sNLuTM%DIbj8Ij~cAoGU&EBrqL;rBwQSho@gg)IEv)%;sPGP7H*;lc&{daGeO7v{AzZl>;JG z=MWu2H$iny$J>l`>U=$aJCGm{6*n4EQ5dYsUXgN4`~F2TCXBkmu>|ipHRsL@*R+HJL`vRHmgEQjZv^8 zkRD?c90+6%Y&~Bb4J2XsYaWn6gKGhhuxFnbBDAM?k`czrF*~tz#XvbfX_anMVKY1cdzH`C>mH=`H=E z;0PdHhQh-@EThgTAj8J!J|DdAuh5pkQ$?gTLURE+O-RiRhk`HtpkAcYONA- z6p$vPpHBkve9*6!Rv^~q{$4!`NR?5}#Xw4p`rH7d&#>tOQm&Or><)S)0aR7jT)|Z5Im^aL-FV$8V8x6zg^qFCZm0a`xuK0pAeK?X!+<38$}<^V z6r+0uIt(wL0-IGvOB;cd?&yzoDIg`f6`_P$7OXLpa2{;>f_@MF5=f06-E^Enrz*;f ze(r+}zaLvgo8>^(IQl|v0JD2FPS}kPrDQrs5W%Uv=;Si`r zm!q!gp*IXgZ3&wm!>0!VDKXZfM**R_dR~r_jp3aXkPgE;=K!JP<+=_?rD1bBkgVbN z`+!vImQwx!LUd#c;iwiTMXYY4?XSY7SNjWRgkqF4Y_#-a*pwP-S+5!jH|nz)kSvy! z-u%83kc$I;WEzl8BUd$$v{C0{f%F@grUrK~!L#kqdkZ)kN9Y=({gSqh}q zDCbHbd|#YW)XhM$`Y0gP+MdAmB&*CAgMWdIWq9y;AZe`@D86n1OcF*PzDK#X@WwB0NUO_e=}xd&W8|s=lGU*eyw)5b^K?0c%mdP7WuQ-DGYF z5F`I28;aR_yS1)4)`rW}u4yvfsJ25Px)W_tC>CFcyA0}UQHvJb50R{i#Os?e&=SdL zs1AE^6GcU`K9Y(|tw=^25~*Z`mot`XPPNr1TT`Ki)?^*3GrHm8__*xa+FM7mJE|qp z7(EoXM2tigNhCt4#fhlZ5{bjK9^1lHt=@C%>Yh6m*2f%m?2-QyI_lUH=FXZkCp7!; zLr*+1bj+-|HHRO6ys&MFq?!=fRo|f|d3(=YHsO3FMNyQeD&z=41j-#=RV2ov1Q=~0aSC?vqSaNC*s)w)Wt_^BI zh_0v1k06ldnl;ATL(z`9Xd)GBjfa|C<>XqqLThcVhixJ?vR$kt5ehk!bX$%n#<`_0 z9~#MHODDReZ48H+{}YQJlhdWms`nN_HD+I<->1$yY}PER!ufR+{ZfN=lu?>9;&O(! z9)NB^{z2^@w|X2a*DP6r_9$vK^h2S>y1Gy@+KAB|O@{nneKZGlyvX+w)ip;W@%BWB zx0_od^?IW%0x9vHNWHtmQui*X9aaODqwddWM*>dQ8JgRg+#U3*9VgRq`;w(m#5f$u zD+|cB1>4Qhh0%ChQz{yZhw9OiNE~4Vfyvu&*l2JPQCoW>A|t)kM3q;S&*#LCQdt;uAx&S7?XbAD^ z=^;*!dYew4dYja%yu}@>x1HANE$X?v8>&;=<9a9cD{r`6>lB5ERM&(!uXj>Y6A{FA zT)o1nGA!=N3*fi)Bt=Zt0wLy5++vrnz~WQZ3DSa?_R4JQWHpilv%D&SZ;@n;%U= z2e~}^`Jjq@N3LR?vV0YE+q;iZ>B`Y6ov%En8BVV{71v!0X*kYP_n?wz)xAyh3rp_0 zCTA~6Jn4*GrwHZGy4FN2TCch+fr$^w@&M<}sZ>ZJg7D-NLV`npYp+YSC*jd(M=BYq zONGv8!_)zsYtj~NZV1(5kdq~8qph_aYYTKkebgZX4+P-!Jqn9vNCbY1qJw2 zdz(e)8mJmH{o!wt#EH@{<6^#}eL!0i0z@@bPShBatK+sAwM;2R6F;vfl+L~Gy zEs$>N^EKH-~CaXnrI~^J@(En^_o8 zZK^1Lhc>ji+NsvblmEZiWXs6rBp;WYKG>khy$s>%T~)`YHl6fD2sJ3nb)<(Q<%wBU~7)G zU=0foHY{m?UeIsN&Cs9Iy*|j2RwNKe5@?js-nMYWy2&X@?H2`K^mFVp>{TF=wOp zVQ4h8FIfVIC`)&Ag#5+B8VeS8AhDPoPdbZ84*E{lI{AF|D7USR27xLc6Owa56TWP3 z#_C`}ETO`|{8&7aT#U78stu7BSA^P}pvc+0@W4^XiR2B*R+IRPZJ1G6mhs5K zSfdkp;5aC>V!DOs(TEOic49ClP|8Tl2hO~ogDC5Lt!B&sAu_=cWkal^0`0^GP4^Us zlPN5=s2&KTP^424Z_{l_o30J7Sh#j=u_ZW;QL7Lfr{H!-YA*wcRuU!T!aV}do!K6Z z*HPHx-;3R0>D$gN$MJ(R$9YB`Mx&{zwZ&OdxwDQFXK}i!jTYyatlSFeP@88Li3}^M zJbTodkOsHM?sRpozx8fQ9Vn>P6rNbhwR)y}i`m5OR% z+&H_Ou5i6Uu3D@X4Q?R_3wr&o4h5K1t-@v7E9x9=B(MtbRu1Zh?Al~&9fAS0T1f*T z*+@~yAKN{|*`q^yo)Ai>8&HCUEF4VTA*ZHP;3_6MLCGJFlCcCu1_yV4`{SFASI$Ut zZE+4Rf@2k|q#J3bYHLM=SQM+r3aXJt1ePgk7&M0Btx3%5AsmY&WAhP>(P?av52Lj} zG){9uJ%#|*BW`KH5d+(>?D8QPaCGl*T~oAffvyHxNdtmODPU2rj?}=J(VJ9l+(edv#4`Im!2#zlhj4fUziLKsptd% zVwsB|Nb`gWJ=P(p(xT3po}GbBze36XSJ`zow{2`u{-J1ODOQq?vP8uit3{;aj~I{y zB}8nGpjv+YJLi@y03p9O*ABABY!iRUeF05FN*NV_ouH}V zlKHoqfvckLLMR=cA8V0)NNRb3fe&pOc-AqA?*_Oqt09eFrQPCm*C=d${Au$>5&urp0eXWPwE5OBEbygj97y{!#3S)o~KjD!Q~nUt?jjl z45?ArF)9HY+6KP)1;AJ4TOya_Zy2qJ#*X%@hMo4p7WxJCC_X@VF{&adItdQK;?vK$ zsp+Os$b!X~*AD}GM`5mVyD5o~NpdKTz~&V~9d@Yq5!xNPzNBI&+|=H!x@bQC-PT2! z<*V}fgDOODoNoBehXJ02=o7Y~c| z1b|}(1GCBA(3#S43l_!M`1ZcIx*Uy>ahFgnn_2*YT_umK)K=Dh#0{~I1$e+(&^Cps zuj$|Pv;s?sab7T|L^SKNd>iRI40co1$G@KxFx&~PFfCaneEbzr4t^GTxwW=MasT~h ze0e=A?ncA!=eNcE@apzV=QF%H$DIC;1_frR5w&eugE=5nBo@@{zBkqO8c#z+hP)13 zq0e~jm5Tk56srv@m-7FyJ7O}%jRaia+0}RovFBy3ZdVM)+?e< zB)CNlCkgCjl_vgWsMg(@;W!7hg6M%#370{{G>y%FFhfwHC zDWBtfyQ!% zD@VeyH{0g1o-4V6bRahu|5^zeqN+Ubn;O-YUuPqgSNZ@|0C6!0bqaH4V~}5jC8Z0n z$O{cJq~#Ab_zS6v0H3HLCYKQv5I0AtPxaBnel3Z_jk?yapOZ(}r*ZU1k+WK}dOo+G zlOykM7WxC3PrYgr-U8a!YyTo+cJ`Y#VzOZ6>K&|VWeAqZW0VIQ~L2#C) zvp-VNOJ$K2?pUUfJ}8}Fo3Zc;4WWKCStP{r1xoZ6YZnwW{dGhR^%wV+Q0EjSZd5Aj z^+bazP-S>tFDJ!x!#h3Xx2TZ`e!fomTD&-PVlF52YgDlA@k@%EZXwLhQ1LM0c!|0f znnFQ?<^Wx3mc|>ASbSuZCwUY&b#U_e^YQ1wCEejGs=eKnIwfZ6s>q}-0L5KGvnqu(n_y~>7adwUC2)6Im%=#VeW}5zk zo=`%?Y_!G-7~t8W-b~g=OgSgc)bZ$9=z@w9cmsbwaXO3RqoTxaQ@8(Mw8_SN`@Dnr zJ%g-;C%f8GoO5aDn8FScL>1==sMJpcI@biGG=xM z^`NMqtc|bzU(eO{-B23rQAMI#N=!rX6+sU(&2R5i60eXJWgI*XzY&wb&dVjaKCbaS@6+ zE&?$d0E#UEg@VcseQ}ErQrO$UNN&6s14fV6m|4YN*78p=5WZ_3;XP*5zpau#6t`6< z2t!*Cror{cotJmhE$)-pL(xdJ2?=Md94BE|Ywuf_v(FWMtjV~qaWfL9GJF&6x za9m6i?82rI2um+BsL(n#J~=+Rp|bc<);l25YiNTS#^LScA6OnBy?j@ZsSTSL_Nw(k zP_q)+^SPw7>yZZ!&Cn$VyVH1`XZ(3(neYj)bvU|_3bNA0;TBwqL z97w&|B6~;-q4FQVq~>{|R)6urPzV&4@HgomS3}8Khq0bxOb`-~6!et@Q$gnO6V2dD zo13G$1bRF~e}9F^3yb1j4c@OHUX1E=@OKS~T`oifAhfAzJ?8R+G?LNQVYKmMvJc8c z*fu(%)qvNJ73H#dfcqNeZtO&lrX_46yW*T+N#Xk_MElItLTexbikLQMpSNUxeUi&N z^rxOE)ZbtTXS}XhX7-=512~JUlW-I5xidLqs2x4%MOu5HIv0sN!25(Sd?Q8}VesOL z?g`UyQ#i2QMU8Xbi46EivpErWatu{oor>&>-|r|+6`uC#upgQ(tsuz7j7-~tUb za~|c>Me!EgZmys243>ijzqOKd7bUOrmjo`xiv~l6IgQwW)<#pPllZ_BfkiQCY^MS< ziIk%98n1sK4n%Ehjld%a{8Uq>lSJ?)TxM1gDt-VW)GfmOr&Q#$qL`M1x}c6_tZ>?( zKbI4bl}xS4WE84NBE3!!^Npg}mluwyBp+6#6&*Tx?y+`2K+hSpk%0G=EwI0I>Iuoi z+86PT063bU+S}D(_E@1`Rwx1M*!}cyTy7Q6S_;Zs@xl{*O8H(00Qzl> z{EML2hJ^7Q{q<4yxOSX^W1n_Q9L0Iz{*E%xO!S+QHsrVvcugImOtO7gi8IL20JcQ7 z)ae+iuYf%+$>UJ@OnqiD2-5Lv$~`bJKv+636OJ4u?nHzNS+_J3~4;HWf645LE{jM~e`(sjhUCLq-(C$551c5Am7E`@WlhCH5%R z4}Z|ii1=kXT>w8uB3A4+wXcO$?i1fF;N?j`v0cjw5j!$2MiBA3Ap7Nko~dA>Ul_KC zc;w^bUnE4NgMe+DSOf}XE=<7*ESfvM_PUZKS8IZk$`0rHG($Ph?f~48CgWg z7uUmMJXFTGFK7FMTXm7d zA!VAG45X51y{W3uT3KjdWN5P?( z2PSne5aD!$=dw_wryB2JntjotInBqeW=j`h-`}~$6opzL@gUEN6GN0L902Q^R>Z_(Q>35i^Ddt8Yruw z+a%GnvSKmYQRjg!B3i*Nwml$rA+ojA@R@8MzT4~2(yn`aAIaET@U@9iDz2B^%B`It zjYa(~Eb%koIS6Vkju=Dx+=7`O15}$Evr${N?KAH`T?>Eb1_F0vpKu_;f`7-48S0$$ za=H&dwX`B$aw|7(cA_>iJ1M$TC_47|EgZGV*#?NWg1j3s8~8E$UjT7Ze*~AlWoJhs z;$0{Dlp3IIvtWW$mX)Soi!#Hir1NXpwZ6Jy{YB8=7ZJMn&)l$)^)^T}3Cx!TG<2Na zJQY+yoOev%)Fq(pHPr0_ELeSEXMFTd_8<7-{q|#80-A7#c&;y!}i-U%yq?c-$YdL9T?gl zh)n`|qdmbg%-dv5YI^IDO&6`2d=R!z|0f)sO(Ls8MQyQ7YRxAv;GQlti5lrClXy-?X7fDn)45 zroDuUw9u;6Z{|8PjQKeCegA&<_xHzl9y!-F&w0&z-t(Th=DMzPU8kj7TWeVv83rdA zW<1l9!<1p17q;wMu)7vaSEdW&$P>Mq$%}gz&J#ti;`7AvditQ0C*sx^7nE>Qp;F9E z6_wP$z4(GKL!MXx?(#$z^Ll{odDs{)2{DN*w+W=$yRbm)xC&I~iOP|MxW=Zi?rqBV zvU2V!o>++|c2?qv?9zFnc?Wr7o(9Nw1Njpmp9}IFkk<$K0+27|iKh?ei7f^LkFWDY zj`zge^kvmQMci~TH$(5s(xxU6H=~%FBU8*h4cv4DIQ6_NXo~QsOI!Zbb#0-!K+muN zfPE1=*6?|QG}$-_62O6jV-F--oSfgH`cjyh*zpU_2>brC z$6(f?Df{oH(oA0LJ7*KXSKI^Nm}rDKi?kC zu<%S+fNwzH;s8*j1R1DT z!ti}U+CE++{rK;WblfK?R*>rw@1z`Uap&M5F~Y$-aXj2pKh3Nt5cWnnUfZ?AJK%tT zK1xC=S!fIjaUf7+BmhRQ1>oj1n;Vc+jw_I>Q(%uHgF?~cB+EuLN^Q5_)&kTfld=@T z(^jjcu+?eH0$cz*1gDiUa9Sy4&#q$b!}CMP=_2Ab^5UW!8TA!&z*4{ybHVv$I+$tz zC-G#!7Sy|myG<0A@?^@2*$R!kG2Dk?rbJm8FG&qf%(iQmNov;GNZM7H1}bsI=cr}RxpTThlEw)0`<7%&@Pk>;y&a70jOOM^7X)pf)G`(SI|u3qU)J3 zaADEhr8fMko5@!G4x)4k?A7p+RAs@{05l1LMs(Z}o=xi|uGfJ{^{s1>y^J&o@bDsO7Mz{y;4B7%BdIJIT6i_@4aPQw99wV>;)yDFqQVmH3Dyz$ zIPMA1(ur2iq#$QNOBHd^Cm0;k4sxK^(I;fWzyiiiA>6I~0#8)j6Y${jEaSz!1;-dz zJ(@e1s{tBg4>Fmu^Kd^8HqQJ0jptjS!80g=K7mD$cdUb0LDekMuI>1sh6uCk1DwV>J6f~e9GZV_uh7xW7ZVi9W~8LU+ql6l&^P{nbJK)oW+a@0M^ z!X$bMmc@U4Bgg>2ZV2l@c4sICXFrGMx1xfMHle{Ldb`nSh7ooE7T_Lx*&5atbM+ND?83s9;nA+$^G}AVpO0b#BsqD2p%g)zj5>b2&q;coqh7m3J1%xkf|KIuoMZlMTrES}n3TPeA0h#2u zb8r$f>hatEG&TJPlTpl0VsyvQ@(mk22et8~$8->0MMjmG8Ytw1garin1bA_L0yyp* zp&-QHC&1mWJtOq=5(wRe!Vs_*iuQWCn46e-Gd(>SpFmHcAJfw%6#VJ&#~Aa#)?^C! z2xIhkW_osJdNV<0_z3@=F2jcUGaS884*VDbw~XFESPkGIj1l7(>dgfC1PPc0fg!#O zKP3KZ>}>mAI4EEu?U2M1o+M!Mf){)s;e2?izmu<@16MQc%=Zr;o;^Fe z_Vkly{%4~tA~sp-wX=*+(v&-i(tY!OEOfK|_qkJ>D2`aPZLw zD+h(t4Y|7QOWxUDja7a}oRVuqsr$T--#J;Xb!OpvWz9YcFE`CiR1SYuKmN>Jx5UE7 zW1cB~(@UvU+%qE9T7HIXmWHnKb?fO?ZXK3Sl7HPd#k#^kK1u$yj&luxWH$m;g>bc52ij=E><)*GH$+y1g@tl;8eg@~0FQyPve z&!1KiU%FtzqR!51mVDC)Hx8M+ELwin%JCX|Hx&4aK3j&YD%h48Ba^3`ak*wqN9Q-@ zMm+V{ulu&F*t^!EXF}wuEln(LeEML*F1J2ZfYF?FLQPZnR(4SJqU=W?8L#F~^&K zJNSgw=_voJ8xI?F8si-7#O;(}YZ!A|kK~_7;`&~a=VtmAE-dYpiPGwJfbq>tp z8O~d%vQASkS+jH2-j0(7i}nr|<;>apJR!f`xPcR@iwE@mKC;4clkVdEO|cbY%jT+V ztO?2QQ#@sA%82xi?QU9WNA9fHk?}A?^}WNdsRzR{J3Q!SZ(=*zVMYhB{>r{rcdZXe znJ`*&W{1l<96`@f%G~6I*V%KeP+wA`q=55y6zPmo_j#6Le^fB!PCV9U~lnfiRtaFz4U23&G zPAe<2=tyrZ+5SEBUhHuGRXF}pm&e8~E>kpv9csR64PVJujMzJ&Y=YhfnT_3Y1rAUA z$}aOxyC5`<% zu|6ix#$U<_SGu{mcD`=Z_FvnlH+6e?A)?~ELimb$Z9Vht%KAA++s*j7+@x=HeaO^Z zX>SZ{O+7R(CfS~}cQ&X!SUULO#r@r1Raf&96nd9;{50A+wR&9l3fqgRD{G&$PupR8 zUq(gf*tJH{Fev`nQ01B7XL64|zWXEfz{iMgV_pW_yOT6IPo&o1vHrZlbFG@KBTqif za{9isho>iZ5Kqi1InFFBm{Y=wDcOquC3h51E0KUEB^>~j2AdB~)y35mhxm%Z~` z1zXEUb3*4>Uje!*lkIRjVCzL$+O8o_0MmRc+r1vESV3BO)`;9J^k6|E&w?(dQZc z3|^ZQSnVy-%OBcHPp>Vl*r`D` zar4Xlw_O!)LOZHyy_81oLm-~KB+D$<|_v=!_4S#kzX?U2= z)OqfxbF)ghyGM|V&6w@C;{Nbup51seWBGffu4O?M;iF2|^sZiF_G3@w!j#9GeY~E& zJXOdyv%RVo?wF^dkr2N6roeSpWp}m2Jkj|}!Wq@mB7Og!v};hh68eU}IA&k*C+E0h z3V+{(&8}7JHt^w__`1@BMTW7m*W_{Ciel*jYYd7|6`q6h=W{ueV#^sT{n_!CjtU;f$eolA!Id9IK8T}01 zOPub#>?(R<>D_LZaBS9&Q^gfc?Na)w9-F;&?g6`56R+??W zk5|;aMdODa9DDv-|EV|P<^{WZFYlH6=TYO6IupN0)tHdWqgMOAUAikg6Mn;n&zlUm zy@3hm!&3$JS7sFsRqZu0S8df^JG(8@Ii}fazPZ%}cWlnQc4<`j@O#AOs*G`uru9p* z?k8gAH%{33Womq6KR3<{{eo+wk8zb%Hy2##wl}(%AAhBN&jq83*4U`u4eukj$M&A_ z$ox%9FX>H9{xIx^Jhu9W4@Ge5~K8GDH7ZhlTc!`l|_CZ#$cz@|NYj=6;c3{VwKQStL`N;>bf8OeI z$X0tmiQ(C&ngxP>mc2#JVHQ_R{TnCC<(}R!sbarieTVR#sT;c4IX~(3`RmR~69-?d3Y%jU;m5K#C{DZ?nSpZKGuGv52h z7RUd7J4q4Fho?qwva_A*s9Eyn+)JAeao-cZr>J+cchm2)T>tLoIi4nW4Q6auWc^ss zedX>WvAHI}(;v9ibn$qcq^$HTg;$j(>i@yp)HuMe(tfK?-hIKyao?XQD(pGW{}BEC zY15CNJ42uUe%xK$app-^kCQ2a*|$2UJs%w1UZF6g>El{|wI|~Wy#%wucWud?Z+6ot z_38P!W`D2!ZZc1et}1$UXrxhbuV3A|^vUWFJVzM4di5ji@)1)NUi7xBeAiv{_VS_1 z9G<8kW{ll*3&T3oQ&aPn59{-CLEm0GUmiZ<%w7GqceZ0ko0|tLW^J!bjfw6tsi(E0 zW>5KR;c8E{G6q_`y*YkrPsamw3sx8w8amq7ed=7;u-5UTX-4iAPfNr1ckjn2pY3_E zcaMWzd~?&|dc{5dVvy~sb8bqAIM(o?Blq^;)tjG`2PY;3XaDVJbIb5v|KqhYw|42hSW{qCm17$9cCZ%^r>2lM_)G zo>KOt$DYVR70>yvmA5?L#Xn7Za}4~;$kvFd)&3(xtZFC99hedYDK zZ}(mAb*dW}m!&8)w~CI7`v|A0}vT;?sV2e7Wj} zsC(1G?e@O-{e9BA32|4(rllsmPYv+4JLx~IG2yOBbfk-0joiH#{8_dBRl~d8j#M~S zD){YEmEjjT;qAM7_1kkzGy2cWGI6u?%JF_Z=~?pix`W)`f_p}PS64@=d2LwnC%|6u zo|o#`1iLGy_uJ3RykK(ATIT*st2~w6i^e%jnWdba-_Y&*Q2V+UIuWZbT>K%p6K3CW zY3)MsOU1^p2=R*TyM}(YSUW#?%l_PhpY0!P9bvRG>6*$E`?IoVmivW88U9YP7;g2p zYRZ%Tr%gnS)v;@?-afs*uZvgVw88PqRCWc-{S%z=_W9*GTinmv>^{`-oTJ_MWy3Rb zzjP?H?ow={8adcw?BD`d{=!RPI*E_}7H7vivQQ|Dp11b)=z|A6rkFc-njbm!as8oy z??x}DMC(?Ky5M5EHpPX{SI;@Ly~(k5>a?|U+rJ5oa=i5CxwH9Jp3m0`<@qjkq8TH5 z)chUTy?e+s$Gx6Y5(oKcj8>1bJ8@%rTDF5*xo(#ceucu5W}JiTeEuAJ-Ei7eIhOf+ zpqqEMd`7Uoddb_%U0KK8*Msbm6u47O}%>%b>oD z8(@qPD-!T|9!fDsxV@^IR#V@@Iw8!`)Xw3WYLGE?ps~zrI$?epC zj`|X_V8b-;xmyfgweRunkfGnW^tnn;m9I~kJRs)8!SB1@aw!fZky6imX z{@BcfXPXoP{2l-N`u+XmD0$TrTkemU6B8ZtceT|q>srSl8$&B~PP8|4PnLr7=H#D*AHzDqYCQKE18Hy0m@ICCkoDFL+Y7O2RZuL`p z+|9M`i5@OdnG3vk7+-(=y{J6==-4I4W%6~x_(vb~zWrt2NW;Y2+e^lcig8?!I!Gg> zbOLWh?6Rwayvj2SQ#viFGpJQrK3A~r?V`GKDr?NM=T_}gOmu#=;pnalThe+vX$g`= z4LRNF<=^V&tGw81Rea*erVz71iKB}W1FD~P8W@^!c~+@*gp1CRcke0+ibK!T1uxmc zdz`*`+}WevLAwJg!yTiFr2*imW0^s$ai(QgP&T#;)hj%VhTK|9mARD!)JZ!K3GV|HL)JILw@8A0RV4&nWqj|ju zPfeQPvarxX^?JPDx=xlu$}DvjJD2-j?(%5m?S)SozioOjb=xznfACVPw5%HO}f*?UVrdhLTnV;w$xAoM8{^C;g7g)p}~G z>L%i7&*!^9hCn{^0vXKnE`0WC|d|>#huy*92uS$wb;SGT|CBJyjKzl7W~5 zST9%r(iB*ELI;fmSu3@6+&DS82{J$>DYt+Eklf)1*2vCnE_Z_*q}A}FxjeqPd>P~* zor53E<+;t}>5zj|4L_R8Uo@8&Kn~JF_|aT`x4FCma*)=-kLL2#Y&i!q*f)@h;QYho zJkZA+*=8HMNYg;ZLGB$J1Q?@qtqknmp6MJ{F-RayWQY zfgHXW`v-?Jv2{`gSs6l)72R2mbI=D#8i4dTkCqK)4C3gv1KqYT%rutEH`mAY_=t1B z7N)V14f`p_9z6s=yK)S+-nvYVx;?_Ba*PVzZMBtS*jJ5OF_@8K;1yHr6biDPh&Z#y zB4DxL4}Epqs=_KM9M1o?^ze<+ws^V}en1L8DTTu)pl#W|0yyj!?vFdj!}J*ZL7su; zE4yw0)&Tz6vhyA3N1%zot|Ndcg8FUgJ4oSLfWvk_BRkc=226&CKS19vuU>Np10Jf75?~j~i*MGp>q}UN4 zeLB*!=L4V*kfL8Ag|C*v)1>gzQus9~{DBl+BZdEw!d1a>+txVtkire5@S##TR|~M<~gF z*8muwP*6RB2^I1MAtB6y#UVaI0r6@;5TJqN8v;QgJ^{i7j4O1{)7RD0+t+mgc%;mP z2ttK{A%Yge;N^nmF7bW*1p%Qxpo8eW0&gF_0Cy0$3Y!lM6EX`H_=SPD1%NgTm_h-7 zT?q|x_Y_DxZ=sB*w*b0;;s!kMi4-tlL40>1S()(*^mO+V0vA9tAq&_Y;GE}T5E^mG2W8`ue+v_~L2d?g32(`3Zzzv?LNR1wws7g@OQ~t2fvNhD1pC0{2B= zUV%`1`UrinJ@BrBKi+o_69#$)hJ*+_g_0UxVB&$10+EPJ~o4v z7&Iec>o_#?He%6SM#rPM0L7#^PsYUnoD*Pzmp7fj-*5O^I*^7#2ohLs8Tb?ca~^~s zK@LxWm`{fgBxncTYhvyTAxMzJUxZ-37($S+ovxBBvlMNiz6?|boq@7?&Z-Ux|*K;sIKS}*Mf|LE- zLD|t^YctF~LQlpGUMIl>?ZbOm?EeSKjwuv@1h11|qT>dyV=yPGqR*l9wn&e!=jm~Q*D)}`O>gjr z`*oMF--qDu2~NhXH#i@|1nraYF+?0zBjaO6=*jq4Q+gbqnNsv~C_RpkmlXXXN{{Ww zNzt#S^w|CuDf%=@kK=ztiawLjlkv|Z^kn>R6P%2{ESjuz{JSF#;}5Ii@$E}+xQn^I z6h4gLI!*Z%OFM>q%RJ42TI^3QWhV*QDIoNuovQ>V z=g&uillFfhj{QtR_T|tc6xc7)z8b+v`vVC+hVb893SUidBSOC!aqQ1}#X|=SL~Lk4B4qQg4Vj?(bIAUo%2ao<}B7 z`n^a$iO`P+49}nGlpa4rb(W%crS$mu5&nGzj1Or)fYN_K_qU6r*pH_4V`0ZZikG5K zr1Xmd1)a*kUduk@a7hkE*Sly~SUp@4 z27*7B;5h{*s7Ff$n}2oRWiufgpFGc(&#dVSWmlT&r{d!IDDmdvt`Xt#j$FmoTPZP!UQC=0< z!{btc^4%$Z2>IEc;`sh*7{&4Th87h6jqKP_{0{O5{?9!yVSn)Z8(tJY0lzE(Nl5WS zXdq)Lo`c$5L-DC7&f6)Dzu(61S7Co1BHbxU{}%aEMDepI{3x)!!hyA>c{OLq-f0XY-aWgc322;Er%8#b_YZPZ|icgdb3p11Ar;vR&ijP74 z!hT`@+avq%Jp-69?~cZCCB+{i`}q5RtjFKuXHoj8D1VOPUr@WRDgFz^vw`A+kpD8M z9JhTfqd0y(WK41Rz6ng@DQ<-L6pCL#?K)Gu9_a-XUneoogit&P z*;z{QxoBP{Qv4IjAE$UfG>&H}j=x_krTA7fzV|8K1Nl=)adl+>H^n=n@l{6l@OZ@| zeHV(uYblueQT!>=52bhlisv|rUq^g0#kt6i6UEn|JfGrQQGbFdJ_y-~q4*0FA8Zfz z7eCL~LFs#={1J+eNA@!*J^|UkL~|79cN9-Vc9c*(><^AF{vIAqC)8Co{@RrOJSsFm z9O_Y1tlosuk3{nmzki4A<2p8!ejf6FCSe~oiQH%AQhHamRffUe|6_l!{a{Mph~`5y zVIOKa$W8*K|A7oi{s)_u^)MFcH&Xfz=)AC<;;x9}=MFgjnaIu|N`D2#;RMC;`%nw`(hov*swntrphV?>Z{}ZLh=cm6Ehxb}Abw}fj?F1tKM^n5vs&7m2IVcYP6vyY4NQz&T zG|S-U7r0%#?wqFdBalBgC~k)GwG=l+es)IViS74B?GB^(7c?KHQXH=@e2Q;H_Lor{ znP*Zc{uKFlj^gGAWky_DXrlSF@t(!+aNm@ZTL zIHa$oxH`I@SA~HD3CHsY@>3IW>?eLNcL1f|isETV>GAu$6DfUjJSn{!>Oe5X{SaSI z*;$0Y3lRT|IF8Rc^n9W#dJclQ5&BZZjN%>9 zmliG*&qsVI#s46lM)7tiKF1ML?Z(7f$T@eU}? z#uU#$+=Ajg(fkRfIDRj15#l(`_;)eeC_U~Me*T61#Qn;l^noaz1(bdKdz@-YkL`b= zIJPf?j(gnh9TYdb9$^3R?|=qUdTf6b#j$-Gil0I2q%GpuKK{Ndh|**GF%-x4lPK5B|PJ5XbS^8G137v%?1JQ3xMD2}h^u{~`6IMR)v^d%^7 zLGgPi&!zZNl%GuTYLuTw@%JbXpIN|!{rM`%GUWH|Fb;nZpO3a!-wp;4Bu~kv*^VaS z-W12{fIr3iA$(~m4V-yf56c~a3 zlE9GtffmYp1%w#|g#?11uYlirN$d)|T^EG7`wP%O{g)dKs1HMi&m-8J1=^wiD=QRU zEMwonmj^kl#|35ZVK+!_T9U0M*uc8za*=)46PCd94&-S1LBu9~SOFxgm*iT1w+Y!` zq@n8%MfLG{4A$kw?Xpe`Zzxi*T(>D@Ar}H45c{R7Qvjs zep~)K^IO-4{==^dX#ax&Ys-Hn4k!Rg4H_pBu8)x)*lDZ%RjB=BG%;ZN@YWC4$MK5> z47NWM7l3`3y6H-`J*2dcPLscFuvLiOqKr^3WsK{o07xv0JpRY2D-0`*~tEx;d{x_L`- z_*Mi*{h^v*D;5l5H;e|V0GFYT;E%4a3>dw3z?x;l;3r7b_|x%&HruMd Q%!jSb+?8yaKk54a2a60rj{pDw literal 0 HcmV?d00001 diff --git a/structured_data.c b/structured_data.c new file mode 100644 index 0000000..3adb8ad --- /dev/null +++ b/structured_data.c @@ -0,0 +1,479 @@ +/** + * structured_data.c + * Implementation of structured data operations + */ + +#include "structured_data.h" +#include "builtins.h" // For set_color and reset_color functions +#include + +/** + * Create a new table with the given headers + */ +TableData* create_table(char **headers, int header_count) { + TableData *table = (TableData*)malloc(sizeof(TableData)); + if (!table) { + fprintf(stderr, "lsh: allocation error in create_table\n"); + return NULL; + } + + // Copy headers + table->headers = (char**)malloc(header_count * sizeof(char*)); + if (!table->headers) { + fprintf(stderr, "lsh: allocation error in create_table (headers)\n"); + free(table); + return NULL; + } + + for (int i = 0; i < header_count; i++) { + table->headers[i] = strdup(headers[i]); + } + + table->header_count = header_count; + table->row_count = 0; + table->row_capacity = 10; // Initial capacity for 10 rows + + // Allocate memory for rows + table->rows = (DataValue**)malloc(table->row_capacity * sizeof(DataValue*)); + if (!table->rows) { + fprintf(stderr, "lsh: allocation error in create_table (rows)\n"); + for (int i = 0; i < header_count; i++) { + free(table->headers[i]); + } + free(table->headers); + free(table); + return NULL; + } + + return table; +} + +/** + * Add a row to a table + */ +void add_table_row(TableData *table, DataValue *row) { + if (!table || !row) return; + + // Resize if needed + if (table->row_count >= table->row_capacity) { + table->row_capacity *= 2; + table->rows = (DataValue**)realloc(table->rows, table->row_capacity * sizeof(DataValue*)); + if (!table->rows) { + fprintf(stderr, "lsh: allocation error in add_table_row\n"); + return; + } + } + + // Add the row + table->rows[table->row_count] = row; + table->row_count++; +} + +/** + * Free all memory associated with a table + */ +void free_table(TableData *table) { + if (!table) return; + + // Free headers + for (int i = 0; i < table->header_count; i++) { + free(table->headers[i]); + } + free(table->headers); + + // Free rows + for (int i = 0; i < table->row_count; i++) { + for (int j = 0; j < table->header_count; j++) { + free_data_value(&table->rows[i][j]); + } + free(table->rows[i]); + } + free(table->rows); + + // Free table structure + free(table); +} + +/** + * Create a copy of a DataValue + */ +DataValue copy_data_value(const DataValue *src) { + DataValue dest; + dest.type = src->type; + dest.is_highlighted = src->is_highlighted; // Make sure we preserve the highlighting flag + + switch (src->type) { + case TYPE_STRING: + case TYPE_SIZE: + dest.value.str_val = strdup(src->value.str_val); + break; + case TYPE_INT: + dest.value.int_val = src->value.int_val; + break; + case TYPE_FLOAT: + dest.value.float_val = src->value.float_val; + break; + } + + return dest; +} + +/** + * Free a DataValue + */ +void free_data_value(DataValue *value) { + if (!value) return; + + if ((value->type == TYPE_STRING || value->type == TYPE_SIZE) && value->value.str_val) { + free(value->value.str_val); + value->value.str_val = NULL; + } +} + +/** + * Parse human-readable sizes (e.g., "10kb", "2.5MB") into bytes + */ +long parse_size(const char *size_str) { + char *unit; + double size = strtod(size_str, &unit); + + // Skip whitespace between number and unit + while (*unit && isspace(*unit)) unit++; + + // Handle case insensitive units + if (strcasecmp(unit, "kb") == 0 || strcasecmp(unit, "k") == 0) { + return (long)(size * 1024); + } else if (strcasecmp(unit, "mb") == 0 || strcasecmp(unit, "m") == 0) { + return (long)(size * 1024 * 1024); + } else if (strcasecmp(unit, "gb") == 0 || strcasecmp(unit, "g") == 0) { + return (long)(size * 1024 * 1024 * 1024); + } else if (strcasecmp(unit, "b") == 0 || *unit == '\0') { + return (long)size; + } + + // Try to handle cases like "2.5 KB" with a space + char num_str[32]; + char unit_str[8]; + if (sscanf(size_str, "%31s %7s", num_str, unit_str) == 2) { + double num = atof(num_str); + if (strcasecmp(unit_str, "kb") == 0 || strcasecmp(unit_str, "k") == 0) { + return (long)(num * 1024); + } else if (strcasecmp(unit_str, "mb") == 0 || strcasecmp(unit_str, "m") == 0) { + return (long)(num * 1024 * 1024); + } else if (strcasecmp(unit_str, "gb") == 0 || strcasecmp(unit_str, "g") == 0) { + return (long)(num * 1024 * 1024 * 1024); + } else if (strcasecmp(unit_str, "b") == 0) { + return (long)num; + } + } + + return (long)size; // Default to just the number if no unit matches +} + +/** + * Extract size in bytes from a formatted size string (e.g., "10.5 KB") + */ +long extract_size_bytes(const char *size_str) { + double size_val = 0; + char unit[8] = ""; + + // Try the format with float + space + unit (e.g., "10.5 MB") + if (sscanf(size_str, "%lf %7s", &size_val, unit) == 2) { + if (strcasecmp(unit, "B") == 0) { + return (long)size_val; + } else if (strcasecmp(unit, "KB") == 0) { + return (long)(size_val * 1024); + } else if (strcasecmp(unit, "MB") == 0) { + return (long)(size_val * 1024 * 1024); + } else if (strcasecmp(unit, "GB") == 0) { + return (long)(size_val * 1024 * 1024 * 1024); + } + } + + // Fallback to direct parsing if the format doesn't match + return parse_size(size_str); +} + +/** + * Filter a table based on a condition + */ +TableData* filter_table(TableData *input, char *field, char *op, char *value) { + if (!input || !field || !op || !value) { + return NULL; + } + + // Create a new table with the same headers + TableData *result = create_table(input->headers, input->header_count); + if (!result) { + return NULL; + } + + // Find field index + int field_idx = -1; + for (int i = 0; i < input->header_count; i++) { + if (strcasecmp(input->headers[i], field) == 0) { + field_idx = i; + break; + } + } + + if (field_idx == -1) { + fprintf(stderr, "filter_table: unknown field '%s'\n", field); + free_table(result); + return NULL; + } + + // Special handling for size field - parse human-readable sizes + // Modified to handle both "size" and "Memory" columns + int is_size_field = (strcasecmp(field, "size") == 0 || strcasecmp(field, "Memory") == 0); + long value_size = is_size_field ? parse_size(value) : 0; + + // Filter rows based on condition + for (int i = 0; i < input->row_count; i++) { + int include_row = 0; + + // Handle based on data type + if (input->rows[i][field_idx].type == TYPE_STRING || + input->rows[i][field_idx].type == TYPE_SIZE) { + char *row_value = input->rows[i][field_idx].value.str_val; + + // Special handling for size field with values like "10.5 KB" + if (is_size_field) { + long row_size = extract_size_bytes(row_value); + + // Compare sizes + if (strcmp(op, ">") == 0) { + include_row = (row_size > value_size); + } else if (strcmp(op, "<") == 0) { + include_row = (row_size < value_size); + } else if (strcmp(op, ">=") == 0) { + include_row = (row_size >= value_size); + } else if (strcmp(op, "<=") == 0) { + include_row = (row_size <= value_size); + } else if (strcmp(op, "==") == 0) { + include_row = (row_size == value_size); + } + } else { + // String comparison + int cmp = strcasecmp(row_value, value); + if (strcmp(op, ">") == 0) { + include_row = (cmp > 0); + } else if (strcmp(op, "<") == 0) { + include_row = (cmp < 0); + } else if (strcmp(op, "==") == 0) { + include_row = (cmp == 0); + } else if (strcmp(op, ">=") == 0) { + include_row = (cmp >= 0); + } else if (strcmp(op, "<=") == 0) { + include_row = (cmp <= 0); + } + } + } else if (input->rows[i][field_idx].type == TYPE_INT) { + int row_value = input->rows[i][field_idx].value.int_val; + int val = atoi(value); + + if (strcmp(op, ">") == 0) { + include_row = (row_value > val); + } else if (strcmp(op, "<") == 0) { + include_row = (row_value < val); + } else if (strcmp(op, ">=") == 0) { + include_row = (row_value >= val); + } else if (strcmp(op, "<=") == 0) { + include_row = (row_value <= val); + } else if (strcmp(op, "==") == 0) { + include_row = (row_value == val); + } + } else if (input->rows[i][field_idx].type == TYPE_FLOAT) { + float row_value = input->rows[i][field_idx].value.float_val; + float val = (float)atof(value); + + if (strcmp(op, ">") == 0) { + include_row = (row_value > val); + } else if (strcmp(op, "<") == 0) { + include_row = (row_value < val); + } else if (strcmp(op, ">=") == 0) { + include_row = (row_value >= val); + } else if (strcmp(op, "<=") == 0) { + include_row = (row_value <= val); + } else if (strcmp(op, "==") == 0) { + include_row = (row_value == val); + } + } + + if (include_row) { + // Create a copy of the row for the filtered table + DataValue *row_copy = (DataValue*)malloc(input->header_count * sizeof(DataValue)); + if (!row_copy) { + fprintf(stderr, "lsh: allocation error in filter_table\n"); + free_table(result); + return NULL; + } + + for (int j = 0; j < input->header_count; j++) { + row_copy[j] = copy_data_value(&input->rows[i][j]); + } + + add_table_row(result, row_copy); + } + } + + return result; +} + +/** + * Print a table to the console with nice formatting using Unicode box characters + * Linux version using ANSI escape sequences for colors + */ +void print_table(TableData *table) { + if (!table || table->row_count == 0) { + printf("(empty table)\n"); + return; + } + + // Calculate column widths + int *col_widths = (int*)malloc(table->header_count * sizeof(int)); + if (!col_widths) { + fprintf(stderr, "lsh: allocation error in print_table\n"); + return; + } + + // Initialize with header widths + for (int i = 0; i < table->header_count; i++) { + col_widths[i] = strlen(table->headers[i]); + } + + // Check cell widths + for (int i = 0; i < table->row_count; i++) { + for (int j = 0; j < table->header_count; j++) { + if (table->rows[i][j].type == TYPE_STRING || table->rows[i][j].type == TYPE_SIZE) { + int len = strlen(table->rows[i][j].value.str_val); + if (len > col_widths[j]) { + col_widths[j] = len; + } + } else if (table->rows[i][j].type == TYPE_INT) { + char buf[32]; + int len = snprintf(buf, sizeof(buf), "%d", table->rows[i][j].value.int_val); + if (len > col_widths[j]) { + col_widths[j] = len; + } + } else if (table->rows[i][j].type == TYPE_FLOAT) { + char buf[32]; + int len = snprintf(buf, sizeof(buf), "%.2f", table->rows[i][j].value.float_val); + if (len > col_widths[j]) { + col_widths[j] = len; + } + } + } + } + + // Add padding to column widths + for (int i = 0; i < table->header_count; i++) { + col_widths[i] += 4; // 2 spaces on each side + } + + // Calculate total table width + int totalWidth = 1; // Start with 1 for the left border + for (int i = 0; i < table->header_count; i++) { + totalWidth += col_widths[i] + 1; // Add column width and right border + } + + // Create a buffer big enough for one line of the table + char *lineBuffer = (char*)malloc(totalWidth * 4 + 1); // Unicode chars can be up to 4 bytes + if (!lineBuffer) { + fprintf(stderr, "lsh: allocation error in print_table\n"); + free(col_widths); + return; + } + + // Begin output with a newline + printf("\n"); + + // ---- Print top border ---- + lineBuffer[0] = '\0'; + strcat(lineBuffer, "┌"); // Top-left corner + for (int i = 0; i < table->header_count; i++) { + for (int j = 0; j < col_widths[i]; j++) { + strcat(lineBuffer, "─"); // Horizontal line + } + if (i < table->header_count - 1) { + strcat(lineBuffer, "┬"); // Top T-junction + } + } + strcat(lineBuffer, "┐"); // Top-right corner + printf("%s\n", lineBuffer); + + // ---- Print header row ---- + lineBuffer[0] = '\0'; + strcat(lineBuffer, "│"); // Vertical line + for (int i = 0; i < table->header_count; i++) { + char cellBuffer[256]; + snprintf(cellBuffer, sizeof(cellBuffer), " %-*s ", col_widths[i] - 2, table->headers[i]); + strcat(lineBuffer, cellBuffer); + strcat(lineBuffer, "│"); // Vertical line + } + printf("%s\n", lineBuffer); + + // ---- Print header/data separator ---- + lineBuffer[0] = '\0'; + strcat(lineBuffer, "├"); // Left T-junction + for (int i = 0; i < table->header_count; i++) { + for (int j = 0; j < col_widths[i]; j++) { + strcat(lineBuffer, "─"); // Horizontal line + } + if (i < table->header_count - 1) { + strcat(lineBuffer, "┼"); // Cross junction + } + } + strcat(lineBuffer, "┤"); // Right T-junction + printf("%s\n", lineBuffer); + + // Print data rows + for (int i = 0; i < table->row_count; i++) { + lineBuffer[0] = '\0'; + strcat(lineBuffer, "│"); // Left border + + for (int j = 0; j < table->header_count; j++) { + // Format cell content based on data type + char cellBuffer[256]; + + if (table->rows[i][j].type == TYPE_STRING || table->rows[i][j].type == TYPE_SIZE) { + snprintf(cellBuffer, sizeof(cellBuffer), " %-*s ", col_widths[j] - 2, table->rows[i][j].value.str_val); + } else if (table->rows[i][j].type == TYPE_INT) { + snprintf(cellBuffer, sizeof(cellBuffer), " %-*d ", col_widths[j] - 2, table->rows[i][j].value.int_val); + } else if (table->rows[i][j].type == TYPE_FLOAT) { + snprintf(cellBuffer, sizeof(cellBuffer), " %-*.2f ", col_widths[j] - 2, table->rows[i][j].value.float_val); + } + + // Apply color if the cell is highlighted + if (table->rows[i][j].is_highlighted) { + strcat(lineBuffer, ANSI_COLOR_GREEN); // Green text for highlighted cells + strcat(lineBuffer, cellBuffer); + strcat(lineBuffer, ANSI_COLOR_RESET); // Reset color + } else { + strcat(lineBuffer, cellBuffer); + } + + strcat(lineBuffer, "│"); // Right border of cell + } + + printf("%s\n", lineBuffer); + } + + // ---- Print bottom border ---- + lineBuffer[0] = '\0'; + strcat(lineBuffer, "└"); // Bottom-left corner + for (int i = 0; i < table->header_count; i++) { + for (int j = 0; j < col_widths[i]; j++) { + strcat(lineBuffer, "─"); // Horizontal line + } + if (i < table->header_count - 1) { + strcat(lineBuffer, "┴"); // Bottom T-junction + } + } + strcat(lineBuffer, "┘"); // Bottom-right corner + printf("%s\n\n", lineBuffer); + + // Clean up + free(lineBuffer); + free(col_widths); +} \ No newline at end of file diff --git a/structured_data.h b/structured_data.h new file mode 100644 index 0000000..15680f9 --- /dev/null +++ b/structured_data.h @@ -0,0 +1,70 @@ +/** + * structured_data.h + * Definitions for structured data representation and manipulation + */ + +#ifndef STRUCTURED_DATA_H +#define STRUCTURED_DATA_H + +#include "common.h" + +// Value types for structured data +typedef enum { + TYPE_STRING, + TYPE_INT, + TYPE_FLOAT, + TYPE_SIZE // Special type for file sizes with units +} ValueType; + +// A single data value that can be of different types +typedef struct { + ValueType type; + union { + char *str_val; + int int_val; + float float_val; + struct { + double value; + char unit[8]; + } size_val; + } value; + int is_highlighted; // Flag for highlighting in tables +} DataValue; + +// Table structure to hold rows and columns of data +typedef struct { + char **headers; // Column names + int header_count; // Number of columns + DataValue **rows; // Array of rows (each row is an array of DataValues) + int row_count; // Current number of rows + int row_capacity; // Allocated capacity for rows +} TableData; + +// Function to create a new table with the given headers +TableData* create_table(char **headers, int header_count); + +// Function to add a row to a table +void add_table_row(TableData *table, DataValue *row); + +// Function to free all memory associated with a table +void free_table(TableData *table); + +// Function to create a copy of a DataValue +DataValue copy_data_value(const DataValue *src); + +// Function to free a DataValue +void free_data_value(DataValue *value); + +// Function to filter a table based on a condition +TableData* filter_table(TableData *input, char *field, char *op, char *value); + +// Function to print a table to the console +void print_table(TableData *table); + +// Function to parse human-readable sizes +long parse_size(const char *size_str); + +// Function to extract size in bytes from a formatted size string +long extract_size_bytes(const char *size_str); + +#endif // STRUCTURED_DATA_H diff --git a/structured_data.o b/structured_data.o new file mode 100644 index 0000000000000000000000000000000000000000..590580fe9805911728a3675da84107e62a2a7cfc GIT binary patch literal 26904 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 +#include +#include +#include +#include +#include +#include + +// Predefined command argument types for better completion +static CommandArgInfo command_arg_info[] = { + {"cd", ARG_TYPE_DIRECTORY, "Change current directory"}, + {"ls", ARG_TYPE_DIRECTORY, "List directory contents"}, + {"cat", ARG_TYPE_FILE, "Display file contents"}, + {"rm", ARG_TYPE_FILE, "Remove file"}, + {"mkdir", ARG_TYPE_DIRECTORY, "Make directory"}, + {"rmdir", ARG_TYPE_DIRECTORY, "Remove directory"}, + {"cp", ARG_TYPE_FILE, "Copy file or directory"}, + {"mv", ARG_TYPE_BOTH, "Move file or directory"}, + {"grep", ARG_TYPE_FILE, "Search file contents"}, + {"less", ARG_TYPE_FILE, "View file contents"}, + {"more", ARG_TYPE_FILE, "View file contents"}, + {"find", ARG_TYPE_DIRECTORY, "Find files"}, + {"chmod", ARG_TYPE_FILE, "Change file permissions"}, + {"chown", ARG_TYPE_FILE, "Change file owner"}, + {"tar", ARG_TYPE_FILE, "Archive utility"}, + {"gzip", ARG_TYPE_FILE, "Compress files"}, + {"gunzip", ARG_TYPE_FILE, "Decompress files"}, + {"zip", ARG_TYPE_FILE, "Compress files"}, + {"unzip", ARG_TYPE_FILE, "Decompress files"}, + {"bash", ARG_TYPE_FILE, "Run bash script"}, + {"sh", ARG_TYPE_FILE, "Run shell script"}, + {"python", ARG_TYPE_FILE, "Run Python script"}, + {"perl", ARG_TYPE_FILE, "Run Perl script"}, + {"java", ARG_TYPE_FILE, "Run Java program"}, + {"gcc", ARG_TYPE_FILE, "C compiler"}, + {"make", ARG_TYPE_FILE, "Build utility"}, + {"diff", ARG_TYPE_FILE, "Compare files"}, + {"patch", ARG_TYPE_FILE, "Apply patch file"}, + {"man", ARG_TYPE_ANY, "Display manual page"}, + {"help", ARG_TYPE_ANY, "Display help"}, + {"alias", ARG_TYPE_ALIAS, "Define or list aliases"}, + {"unalias", ARG_TYPE_ALIAS, "Remove alias"}, + {"bookmark", ARG_TYPE_BOOKMARK, "Bookmark directories"}, + {"weather", ARG_TYPE_FAVORITE_CITY, "Weather information"}, + {"theme", ARG_TYPE_THEME, "Shell theme settings"}, + {NULL, ARG_TYPE_ANY, NULL} // End marker +}; + +// Global state +static CommandContext current_context; + +/** + * Initialize tab completion system + */ +void init_tab_completion(void) { + // Initialize context to defaults + memset(¤t_context, 0, sizeof(CommandContext)); +} + +/** + * Shutdown tab completion system + */ +void shutdown_tab_completion(void) { + // Nothing to clean up for now +} + +/** + * Get the type of argument expected for a command + */ +static ArgumentType get_argument_type(const char *cmd) { + if (!cmd || !*cmd) return ARG_TYPE_ANY; + + for (int i = 0; command_arg_info[i].command != NULL; i++) { + if (strcmp(command_arg_info[i].command, cmd) == 0) { + return command_arg_info[i].arg_type; + } + } + + return ARG_TYPE_ANY; +} + +/** + * Parse the command line to determine context + */ +static void parse_command_context(const char *buffer) { + // Reset the context + memset(¤t_context, 0, sizeof(CommandContext)); + + if (!buffer || !*buffer) return; + + // Make a copy of the buffer to tokenize + char buffer_copy[1024]; + strncpy(buffer_copy, buffer, sizeof(buffer_copy) - 1); + buffer_copy[sizeof(buffer_copy) - 1] = '\0'; + + // Tokenize the buffer + char *token = strtok(buffer_copy, " \t"); + int token_index = 0; + + // Extract the command if present + if (token) { + strncpy(current_context.filter_command, token, sizeof(current_context.filter_command) - 1); + current_context.filter_command[sizeof(current_context.filter_command) - 1] = '\0'; + token = strtok(NULL, " \t"); + token_index++; + } + + // Get the last token (current word being completed) + char *last_token = NULL; + while (token) { + last_token = token; + token_index++; + token = strtok(NULL, " \t"); + } + + if (last_token) { + strncpy(current_context.current_token, last_token, sizeof(current_context.current_token) - 1); + current_context.current_token[sizeof(current_context.current_token) - 1] = '\0'; + current_context.token_index = token_index - 1; // Adjust token index to be 0-based + } else { + // This handles the case where there's only one token (the command) + // In this case, we're completing the command itself + strncpy(current_context.current_token, current_context.filter_command, + sizeof(current_context.current_token) - 1); + current_context.current_token[sizeof(current_context.current_token) - 1] = '\0'; + current_context.token_index = 0; + } +} + +/** + * Find all files/directories that match the beginning of path + */ +static char *find_path_completions(const char *path) { + if (!path || !*path) return NULL; + + char dir_path[PATH_MAX] = "."; // Default to current directory + char name_prefix[PATH_MAX] = ""; + + // Split path into directory part and name prefix part + char *last_slash = strrchr(path, '/'); + if (last_slash) { + // Path contains a directory part + int dir_len = last_slash - path; + strncpy(dir_path, path, dir_len); + dir_path[dir_len] = '\0'; + + // Handle absolute path vs. relative path with subdirectories + if (dir_len == 0) { + // Handle case where path starts with '/' + strcpy(dir_path, "/"); + } + + // Extract the name prefix part (after the last slash) + strncpy(name_prefix, last_slash + 1, sizeof(name_prefix) - 1); + name_prefix[sizeof(name_prefix) - 1] = '\0'; + } else { + // No directory part, just a name prefix + strncpy(name_prefix, path, sizeof(name_prefix) - 1); + name_prefix[sizeof(name_prefix) - 1] = '\0'; + } + + // Open the directory + DIR *dir = opendir(dir_path); + if (!dir) { + return NULL; + } + + // Find the first matching entry + struct dirent *entry; + char *completion = NULL; + int name_prefix_len = strlen(name_prefix); + + while ((entry = readdir(dir)) != NULL) { + // Skip "." and ".." if there's already a name prefix + if (name_prefix_len > 0 && (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)) { + continue; + } + + // Check if this entry matches the name prefix + if (strncasecmp(entry->d_name, name_prefix, name_prefix_len) == 0) { + // Construct the completion + char full_path[PATH_MAX]; + + // Check if we're completing from root or relative + if (dir_path[0] == '/' && dir_path[1] == '\0') { + snprintf(full_path, sizeof(full_path), "/%s", entry->d_name); + } else if (strcmp(dir_path, ".") == 0) { + snprintf(full_path, sizeof(full_path), "%s", entry->d_name); + } else { + snprintf(full_path, sizeof(full_path), "%s/%s", dir_path, entry->d_name); + } + + // Check if it's a directory, append slash if it is + struct stat st; + char path_to_check[PATH_MAX]; + + if (full_path[0] == '/') { + // Absolute path + strncpy(path_to_check, full_path, sizeof(path_to_check) - 1); + } else { + // Relative path, construct with current directory + char cwd[PATH_MAX]; + if (getcwd(cwd, sizeof(cwd))) { + snprintf(path_to_check, sizeof(path_to_check), "%s/%s", cwd, full_path); + } else { + strncpy(path_to_check, full_path, sizeof(path_to_check) - 1); + } + } + + path_to_check[sizeof(path_to_check) - 1] = '\0'; + + if (stat(path_to_check, &st) == 0 && S_ISDIR(st.st_mode)) { + char *dir_completion = (char *)malloc(strlen(full_path) + 2); // +2 for slash and null + if (dir_completion) { + strcpy(dir_completion, full_path); + strcat(dir_completion, "/"); + completion = dir_completion; + } + } else { + completion = strdup(full_path); + } + + break; + } + } + + closedir(dir); + return completion; +} + +/** + * Get the completion for a command + */ +static char *complete_command(const char *prefix) { + if (!prefix || !*prefix) return NULL; + + // First check builtins + int builtin_count = lsh_num_builtins(); + + for (int i = 0; i < builtin_count; i++) { + if (strncasecmp(builtin_str[i], prefix, strlen(prefix)) == 0) { + return strdup(builtin_str[i]); + } + } + + // Then check for aliases + int alias_count; + char **aliases = get_alias_names(&alias_count); + + if (aliases) { + for (int i = 0; i < alias_count; i++) { + if (strncasecmp(aliases[i], prefix, strlen(prefix)) == 0) { + char *result = strdup(aliases[i]); + + // Free the alias names + for (int j = 0; j < alias_count; j++) { + free(aliases[j]); + } + free(aliases); + + return result; + } + } + + // Free the alias names if we didn't find a match + for (int i = 0; i < alias_count; i++) { + free(aliases[i]); + } + free(aliases); + } + + // Finally check for executables in PATH + char *path = getenv("PATH"); + if (!path) return NULL; + + char *path_copy = strdup(path); + if (!path_copy) return NULL; + + char *result = NULL; + char *dir = strtok(path_copy, ":"); + + while (dir && !result) { + DIR *dirp = opendir(dir); + if (dirp) { + struct dirent *entry; + while ((entry = readdir(dirp)) != NULL) { + if (strncasecmp(entry->d_name, prefix, strlen(prefix)) == 0) { + // Check if it's executable + char full_path[PATH_MAX]; + snprintf(full_path, sizeof(full_path), "%s/%s", dir, entry->d_name); + + struct stat st; + if (stat(full_path, &st) == 0 && (st.st_mode & S_IXUSR)) { + result = strdup(entry->d_name); + break; + } + } + } + closedir(dirp); + } + dir = strtok(NULL, ":"); + } + + free(path_copy); + return result; +} + +/** + * Get completion for the current context + */ +char *get_tab_completion(const char *buffer) { + if (!buffer) return NULL; + + // Parse the command context + parse_command_context(buffer); + + // If we're completing the first token, it's a command + if (current_context.token_index == 0) { + return complete_command(current_context.current_token); + } + + // For subsequent tokens, look at the command to determine what to complete + ArgumentType arg_type = get_argument_type(current_context.filter_command); + + switch (arg_type) { + case ARG_TYPE_FILE: + // Complete file names + return find_path_completions(current_context.current_token); + + case ARG_TYPE_DIRECTORY: + // Complete directory names + return find_path_completions(current_context.current_token); + + case ARG_TYPE_BOTH: + // Complete both files and directories + return find_path_completions(current_context.current_token); + + case ARG_TYPE_BOOKMARK: + // Complete bookmark names + if (current_context.current_token[0]) { + int bookmark_count; + char **bookmarks = get_bookmark_names(&bookmark_count); + + if (bookmarks) { + char *result = NULL; + for (int i = 0; i < bookmark_count; i++) { + if (strncasecmp(bookmarks[i], current_context.current_token, strlen(current_context.current_token)) == 0) { + result = strdup(bookmarks[i]); + break; + } + } + + // Free the bookmark names + for (int i = 0; i < bookmark_count; i++) { + free(bookmarks[i]); + } + free(bookmarks); + + return result; + } + } + break; + + case ARG_TYPE_ALIAS: + // Complete alias names + if (current_context.current_token[0]) { + int alias_count; + char **aliases = get_alias_names(&alias_count); + + if (aliases) { + char *result = NULL; + for (int i = 0; i < alias_count; i++) { + if (strncasecmp(aliases[i], current_context.current_token, strlen(current_context.current_token)) == 0) { + result = strdup(aliases[i]); + break; + } + } + + // Free the alias names + for (int i = 0; i < alias_count; i++) { + free(aliases[i]); + } + free(aliases); + + return result; + } + } + break; + + case ARG_TYPE_FAVORITE_CITY: + // Complete favorite city names + if (current_context.current_token[0]) { + int city_count; + char **cities = get_favorite_city_names(&city_count); + + if (cities) { + char *result = NULL; + for (int i = 0; i < city_count; i++) { + if (strncasecmp(cities[i], current_context.current_token, strlen(current_context.current_token)) == 0) { + result = strdup(cities[i]); + break; + } + } + + // Free the city names + for (int i = 0; i < city_count; i++) { + free(cities[i]); + } + free(cities); + + return result; + } + } + break; + + case ARG_TYPE_THEME: + // Complete theme names + if (current_context.current_token[0]) { + int theme_count; + char **themes = get_theme_names(&theme_count); + + if (themes) { + char *result = NULL; + for (int i = 0; i < theme_count; i++) { + if (strncasecmp(themes[i], current_context.current_token, strlen(current_context.current_token)) == 0) { + result = strdup(themes[i]); + break; + } + } + + // Free the theme names + for (int i = 0; i < theme_count; i++) { + free(themes[i]); + } + free(themes); + + return result; + } + } + break; + + case ARG_TYPE_ANY: + default: + // By default, complete file and directory names + return find_path_completions(current_context.current_token); + } + + return NULL; +} diff --git a/tab_complete.h b/tab_complete.h new file mode 100644 index 0000000..0e47b13 --- /dev/null +++ b/tab_complete.h @@ -0,0 +1,58 @@ +/** + * tab_complete.h + * Functions for tab completion and path suggestions + */ + +#ifndef TAB_COMPLETE_H +#define TAB_COMPLETE_H + +#include "common.h" + +/** + * Command context structure + */ +typedef struct { + int is_after_pipe; // Flag if cursor is right after a pipe + int is_filter_command; // Flag if current command is a filter command + char cmd_before_pipe[64]; // Command before the pipe + char filter_command[64]; // Current filter command + char current_token[1024]; // Current token being typed + int token_position; // Position within current token + int token_index; // Index of current token in command + int filter_arg_index; // Argument index for filter command + int has_current_field; // Flag if current field is set + int has_current_operator; // Flag if current operator is set + char current_field[64]; // Current field if known + char current_operator[16]; // Current operator if known +} CommandContext; + +typedef enum { + ARG_TYPE_ANY, // Any argument + ARG_TYPE_FILE, // Files only + ARG_TYPE_DIRECTORY, // Directories only + ARG_TYPE_BOOKMARK, // Bookmark names + ARG_TYPE_ALIAS, // Alias names + ARG_TYPE_BOTH, // Both files and directories + ARG_TYPE_FAVORITE_CITY, + ARG_TYPE_THEME, +} ArgumentType; + +/** + * Structure for command argument type information + */ +typedef struct { + char *command; // Command name + ArgumentType arg_type; // Expected argument type + char *description; // Optional description +} CommandArgInfo; + +// Main tab completion function +char *get_tab_completion(const char *buffer); + +// Initialize tab completion system +void init_tab_completion(void); + +// Shutdown tab completion system +void shutdown_tab_completion(void); + +#endif // TAB_COMPLETE_H diff --git a/tab_complete.o b/tab_complete.o new file mode 100644 index 0000000000000000000000000000000000000000..f22a705651a8d5ea9cce8a86987172797222e98f GIT binary patch literal 24232 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 literal 0 HcmV?d00001 diff --git a/themes.c b/themes.c new file mode 100644 index 0000000..696f7d3 --- /dev/null +++ b/themes.c @@ -0,0 +1,481 @@ +/** + * themes.c + * Implementation of theme system for shell appearance + */ + +#include "themes.h" +#include +#include + +// Define Windows colors for compatibility +#define FOREGROUND_BLUE 0x0001 +#define FOREGROUND_GREEN 0x0002 +#define FOREGROUND_RED 0x0004 +#define FOREGROUND_INTENSITY 0x0008 + +#define FOREGROUND_CYAN (FOREGROUND_GREEN | FOREGROUND_BLUE) +#define FOREGROUND_MAGENTA (FOREGROUND_RED | FOREGROUND_BLUE) + +// Current active theme +ShellTheme current_theme; + +// Define built-in themes +static ShellTheme default_theme = { + // Standard console colors + .PRIMARY_COLOR = + FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, // White + .SECONDARY_COLOR = + FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, // White (dimmer) + .ACCENT_COLOR = FOREGROUND_GREEN | FOREGROUND_INTENSITY, // Bright Green + .SUCCESS_COLOR = FOREGROUND_GREEN | FOREGROUND_INTENSITY, // Bright Green + .ERROR_COLOR = FOREGROUND_RED | FOREGROUND_INTENSITY, // Bright Red + .WARNING_COLOR = FOREGROUND_RED | FOREGROUND_GREEN | + FOREGROUND_INTENSITY, // Bright Yellow + + .HEADER_COLOR = FOREGROUND_GREEN | FOREGROUND_INTENSITY, // Bright Green + .STATUS_BAR_COLOR = 0, // Black + .STATUS_TEXT_COLOR = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | + FOREGROUND_INTENSITY, // Bright White + .PROMPT_COLOR = FOREGROUND_CYAN | FOREGROUND_INTENSITY, // Bright Cyan + + .DIRECTORY_COLOR = FOREGROUND_GREEN | FOREGROUND_INTENSITY, // Bright Green + .EXECUTABLE_COLOR = FOREGROUND_RED | FOREGROUND_GREEN | + FOREGROUND_INTENSITY, // Bright Yellow + .TEXT_FILE_COLOR = + FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, // White + .IMAGE_FILE_COLOR = FOREGROUND_RED | FOREGROUND_BLUE | + FOREGROUND_INTENSITY, // Bright Magenta + .CODE_FILE_COLOR = FOREGROUND_BLUE | FOREGROUND_INTENSITY, // Bright Blue + .ARCHIVE_FILE_COLOR = FOREGROUND_RED | FOREGROUND_INTENSITY, // Bright Red + + .SYNTAX_KEYWORD = FOREGROUND_CYAN | FOREGROUND_INTENSITY, // Bright Cyan + .SYNTAX_STRING = FOREGROUND_GREEN | FOREGROUND_INTENSITY, // Bright Green + .SYNTAX_COMMENT = FOREGROUND_INTENSITY, // Gray + .SYNTAX_NUMBER = + FOREGROUND_MAGENTA | FOREGROUND_INTENSITY, // Bright Magenta + .SYNTAX_PREPROCESSOR = + FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY, // Yellow + + // ANSI colors for default theme (basic colors, not true full 24-bit colors) + .ANSI_BASE = "\033[37m", // White + .ANSI_SURFACE = "\033[37m", // White + .ANSI_OVERLAY = "\033[37m", // White + .ANSI_MUTED = "\033[37m", // White + .ANSI_SUBTLE = "\033[37m", // White + .ANSI_TEXT = "\033[97m", // Bright White + .ANSI_LOVE = "\033[91m", // Bright Red + .ANSI_GOLD = "\033[93m", // Bright Yellow + .ANSI_ROSE = "\033[95m", // Bright Magenta + .ANSI_PINE = "\033[92m", // Bright Green + .ANSI_FOAM = "\033[96m", // Bright Cyan + .ANSI_IRIS = "\033[94m", // Bright Blue + .ANSI_HIGHLIGHT = "\033[37m", // White + + // Don't use ANSI colors for default theme + .use_ansi_colors = FALSE, + + .name = "default"}; + +static ShellTheme rose_pine_theme = { + // Legacy console colors (for backward compatibility) + .PRIMARY_COLOR = + FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, // White (base) + .SECONDARY_COLOR = + FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, // Muted + .ACCENT_COLOR = FOREGROUND_BLUE, // Blue for git syntax + .SUCCESS_COLOR = FOREGROUND_GREEN, + .ERROR_COLOR = FOREGROUND_RED | FOREGROUND_INTENSITY, + .WARNING_COLOR = FOREGROUND_RED | FOREGROUND_GREEN, + + .HEADER_COLOR = FOREGROUND_RED | FOREGROUND_BLUE, + .STATUS_BAR_COLOR = 0, + .STATUS_TEXT_COLOR = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | + FOREGROUND_INTENSITY, + .PROMPT_COLOR = + FOREGROUND_RED | FOREGROUND_INTENSITY, // Bright red for repo name + + .DIRECTORY_COLOR = + FOREGROUND_RED | FOREGROUND_INTENSITY, // Bright pink for directory + + .EXECUTABLE_COLOR = FOREGROUND_RED | FOREGROUND_GREEN, + .TEXT_FILE_COLOR = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, + .IMAGE_FILE_COLOR = FOREGROUND_BLUE, + .CODE_FILE_COLOR = FOREGROUND_BLUE, + .ARCHIVE_FILE_COLOR = FOREGROUND_RED, + + .SYNTAX_KEYWORD = FOREGROUND_RED | FOREGROUND_BLUE, + .SYNTAX_STRING = FOREGROUND_GREEN, + .SYNTAX_COMMENT = FOREGROUND_RED | FOREGROUND_GREEN | 0x8, + .SYNTAX_NUMBER = FOREGROUND_RED, + .SYNTAX_PREPROCESSOR = FOREGROUND_RED | FOREGROUND_GREEN, + + // ANSI true color definitions - exact Rose Pine colors + .ANSI_BASE = "\033[38;2;25;23;36m", // Base color + .ANSI_SURFACE = "\033[38;2;31;29;46m", // Surface color + .ANSI_OVERLAY = "\033[38;2;38;35;58m", // Overlay color + .ANSI_MUTED = "\033[38;2;110;106;134m", // Muted color + .ANSI_SUBTLE = "\033[38;2;144;140;170m", // Subtle color + .ANSI_TEXT = "\033[38;2;224;222;244m", // Text color + .ANSI_LOVE = "\033[38;2;235;111;146m", // Love/Red color + .ANSI_GOLD = "\033[38;2;246;193;119m", // Gold color + // Updated Rose/pink color to a soft peach + .ANSI_ROSE = "\033[38;2;255;195;195m", // Soft Peach + .ANSI_PINE = "\033[38;2;49;116;143m", // Pine color + .ANSI_FOAM = "\033[38;2;156;207;216m", // Foam color + .ANSI_IRIS = "\033[38;2;196;167;231m", // Iris color + .ANSI_HIGHLIGHT = "\033[38;2;68;65;90m", // Highlight color + .ANSI_INVALID_COMMAND = "\033[38;2;205;120;120m", + + // Enable ANSI colors for Rose Pine theme + .use_ansi_colors = TRUE, + + .name = "rose-pine"}; + +static ShellTheme catppuccin_mocha_theme = { + // Legacy console colors (for backward compatibility) + .PRIMARY_COLOR = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | + FOREGROUND_INTENSITY, // Bright white for text + .SECONDARY_COLOR = + FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, // White (dimmer) + .ACCENT_COLOR = + FOREGROUND_BLUE | FOREGROUND_INTENSITY, // Bright Blue for accent + .SUCCESS_COLOR = FOREGROUND_GREEN | FOREGROUND_INTENSITY, // Bright Green + .ERROR_COLOR = FOREGROUND_RED | FOREGROUND_INTENSITY, // Bright Red + .WARNING_COLOR = + FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY, // Yellow + + .HEADER_COLOR = FOREGROUND_RED | FOREGROUND_BLUE | + FOREGROUND_INTENSITY, // Mauve color for headers + .STATUS_BAR_COLOR = 0, // Black/dark background + .STATUS_TEXT_COLOR = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | + FOREGROUND_INTENSITY, // Bright White + .PROMPT_COLOR = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | + FOREGROUND_INTENSITY, // Blue text for prompt + + .DIRECTORY_COLOR = FOREGROUND_BLUE | FOREGROUND_GREEN | + FOREGROUND_INTENSITY, // Teal for directories + .EXECUTABLE_COLOR = FOREGROUND_RED | FOREGROUND_GREEN | + FOREGROUND_INTENSITY, // Yellow for executables + .TEXT_FILE_COLOR = FOREGROUND_RED | FOREGROUND_GREEN | + FOREGROUND_BLUE, // White for text files + .IMAGE_FILE_COLOR = FOREGROUND_RED | FOREGROUND_INTENSITY, // Red for images + .CODE_FILE_COLOR = FOREGROUND_BLUE | FOREGROUND_INTENSITY, // Blue for code + .ARCHIVE_FILE_COLOR = + FOREGROUND_GREEN | FOREGROUND_INTENSITY, // Green for archives + + .SYNTAX_KEYWORD = + FOREGROUND_BLUE | FOREGROUND_INTENSITY, // Blue for keywords + .SYNTAX_STRING = + FOREGROUND_GREEN | FOREGROUND_INTENSITY, // Green for strings + .SYNTAX_COMMENT = FOREGROUND_INTENSITY, // Gray for comments + .SYNTAX_NUMBER = FOREGROUND_RED | FOREGROUND_INTENSITY, // Red for numbers + .SYNTAX_PREPROCESSOR = FOREGROUND_GREEN | FOREGROUND_BLUE | + FOREGROUND_INTENSITY, // Cyan for preprocessor + + // ANSI true color definitions for Catppuccin Mocha + .ANSI_BASE = "\033[38;2;30;30;46m", // Base color #1e1e2e + .ANSI_SURFACE = "\033[38;2;49;50;68m", // Surface color #313244 + .ANSI_OVERLAY = "\033[38;2;69;71;90m", // Overlay color #45475a + .ANSI_MUTED = "\033[38;2;186;194;222m", // Muted color #bac2de (subtext1) + .ANSI_SUBTLE = "\033[38;2;166;173;200m", // Subtle color #a6adc8 (subtext0) + .ANSI_TEXT = "\033[38;2;205;214;244m", // Text color #cdd6f4 + .ANSI_LOVE = "\033[38;2;243;139;168m", // Love/Red color #f38ba8 + .ANSI_GOLD = "\033[38;2;249;226;175m", // Gold/Yellow color #f9e2af + .ANSI_ROSE = "\033[38;2;245;194;231m", // Pink color #f5c2e7 + .ANSI_PINE = "\033[38;2;166;227;161m", // Green color #a6e3a1 + .ANSI_FOAM = "\033[38;2;148;226;213m", // Teal color #94e2d5 + .ANSI_IRIS = "\033[38;2;203;166;247m", // Mauve/Purple color #cba6f7 + .ANSI_HIGHLIGHT = "\033[38;2;180;190;254m", // Lavender highlight #b4befe + + // Enable ANSI colors for Catppuccin Mocha theme + .use_ansi_colors = TRUE, + + .name = "catppuccin-mocha"}; + +// Path to the theme configuration file +char theme_config_path[PATH_MAX]; + +/** + * Initialize the theme system + */ +void init_theme_system(void) { + // Determine theme config file location in user's home directory + char *home_dir = getenv("HOME"); + if (home_dir) { + snprintf(theme_config_path, PATH_MAX, "%s/.lsh_theme", home_dir); + } else { + // Fallback to current directory if HOME not available + strcpy(theme_config_path, ".lsh_theme"); + } + + // Set default theme initially + memcpy(¤t_theme, &default_theme, sizeof(ShellTheme)); + + // Try to load theme from config file + FILE *config_file = fopen(theme_config_path, "r"); + if (config_file) { + char theme_name[32]; + if (fscanf(config_file, "theme=%31s", theme_name) == 1) { + // We found a theme name, try to load it + load_theme(theme_name); + } + fclose(config_file); + } else { + // Config file doesn't exist, create it with default theme + config_file = fopen(theme_config_path, "w"); + if (config_file) { + fprintf(config_file, "theme=default\n"); + fclose(config_file); + } + } +} + +/** + * Load a specific theme by name + * + * @param theme_name Name of the theme to load + * @return 1 if successful, 0 if theme not found + */ +int load_theme(const char *theme_name) { + if (strcmp(theme_name, "default") == 0) { + memcpy(¤t_theme, &default_theme, sizeof(ShellTheme)); + return 1; + } else if (strcmp(theme_name, "rose-pine") == 0) { + memcpy(¤t_theme, &rose_pine_theme, sizeof(ShellTheme)); + return 1; + } else if (strcmp(theme_name, "catppuccin-mocha") == 0) { + memcpy(¤t_theme, &catppuccin_mocha_theme, sizeof(ShellTheme)); + return 1; + } + + // Theme not found + fprintf(stderr, "Theme '%s' not found\n", theme_name); + return 0; +} + +/** + * Apply the current theme settings + * Called whenever theme-dependent UI elements need to be updated + */ +void apply_current_theme(void) { + // When called, the shell can update any on-screen elements that depend on + // theme colors. This function would be called when changing themes or at startup. + + // In Linux, we'll always use ANSI colors, as the terminal emulator handles this natively + if (current_theme.use_ansi_colors) { + // Use ANSI true color + printf("%s", current_theme.ANSI_TEXT); + } else { + // Use standard ANSI color approximation of the theme's primary color + // Linux terminals always support basic ANSI colors, so we'll map the Windows color attributes + // to the closest ANSI colors + + int fg = 37; // Default to white text + + if (current_theme.PRIMARY_COLOR & 0x01) fg = 34; // Blue + if (current_theme.PRIMARY_COLOR & 0x02) fg = 32; // Green + if (current_theme.PRIMARY_COLOR & 0x04) fg = 31; // Red + + // Combinations + if ((current_theme.PRIMARY_COLOR & 0x03) == 0x03) fg = 36; // Cyan (Green + Blue) + if ((current_theme.PRIMARY_COLOR & 0x05) == 0x05) fg = 35; // Magenta (Red + Blue) + if ((current_theme.PRIMARY_COLOR & 0x06) == 0x06) fg = 33; // Yellow (Red + Green) + if ((current_theme.PRIMARY_COLOR & 0x07) == 0x07) fg = 37; // White (Red + Green + Blue) + + // Bright variants + if (current_theme.PRIMARY_COLOR & 0x08) fg += 60; // Add intensity + + printf("\033[%dm", fg); // Set the color + } +} + +/** + * Get pointer to the current theme + * + * @return Pointer to the current theme structure + */ +const ShellTheme *get_current_theme(void) { return ¤t_theme; } + +/** + * List all available themes + */ +void list_available_themes(void) { + printf("Available themes:\n"); + printf(" default - Standard shell colors\n"); + printf( + " rose-pine - Soothing, warm color scheme with true color support\n"); + printf(" catppuccin-mocha - Deep dark theme with vibrant accent colors"); + + // Display which theme is currently active + printf("\nCurrent theme: %s", current_theme.name); + + // Display ANSI color status for current theme + if (current_theme.use_ansi_colors) { + printf(" (using true color)\n"); + } else { + printf(" (using standard console colors)\n"); + } +} + +/** + * Initialize themes at shell startup + */ +void init_themes(void) { + // Call the theme system initialization + init_theme_system(); + + // Apply the initial theme + apply_current_theme(); +} + +/** + * Shutdown theme system + */ +void shutdown_themes(void) { + // Reset terminal color to default + printf(ANSI_COLOR_RESET); + + // Currently, no other cleanup is needed for the theme system +} + +/** + * Command handler for the "theme" command + * + * @param args Command arguments + * @return 1 to continue shell execution, 0 to exit shell + */ +int lsh_theme(char **args) { + if (args[1] == NULL) { + // No arguments, show usage info and current theme + printf("Usage: theme [arguments]\n"); + printf("Commands:\n"); + printf(" list List available themes\n"); + printf(" set NAME Set the current theme to NAME\n"); + printf(" show Show current theme details\n"); + printf("\nCurrent theme: %s", current_theme.name); + + // Display ANSI color status for current theme + if (current_theme.use_ansi_colors) { + printf(" (using true color)\n"); + } else { + printf(" (using standard console colors)\n"); + } + + return 1; + } + + // Handle subcommands + if (strcmp(args[1], "list") == 0) { + list_available_themes(); + return 1; + } else if (strcmp(args[1], "set") == 0) { + if (args[2] == NULL) { + printf("Usage: theme set \n"); + printf("Try 'theme list' to see available themes\n"); + return 1; + } + + // Try to load the requested theme + if (load_theme(args[2])) { + // Update theme config file + FILE *config_file = fopen(theme_config_path, "w"); + if (config_file) { + fprintf(config_file, "theme=%s\n", args[2]); + fclose(config_file); + + // Apply the theme + apply_current_theme(); + + printf("Theme set to '%s'\n", args[2]); + + // Display ANSI color status for the selected theme + if (current_theme.use_ansi_colors) { + printf("This theme uses true color for better visual appearance.\n"); + } + } else { + fprintf(stderr, "Could not save theme setting\n"); + } + } + return 1; + } else if (strcmp(args[1], "show") == 0) { + printf("Current theme: %s\n", current_theme.name); + + // Display ANSI color status + if (current_theme.use_ansi_colors) { + printf("Using true color mode"); + + // Show a color demo if using ANSI colors + printf("\nColor sample:\n"); + printf("%sBase %sText %sLove %sGold %sRose %sPine %sFoam %sIris%s\n", + current_theme.ANSI_BASE, current_theme.ANSI_TEXT, + current_theme.ANSI_LOVE, current_theme.ANSI_GOLD, + current_theme.ANSI_ROSE, current_theme.ANSI_PINE, + current_theme.ANSI_FOAM, current_theme.ANSI_IRIS, + "\033[0m"); // Reset + } else { + printf("Using standard console colors\n"); + } + + return 1; + } else { + printf("Unknown theme command: %s\n", args[1]); + printf("Try 'theme list' or 'theme set '\n"); + return 1; + } + + return 1; +} +char **get_theme_names(int *theme_count) { + // Define the hardcoded themes + char *builtin_themes[] = {"default", "rose-pine", "catppuccin-mocha"}; + int builtin_count = sizeof(builtin_themes) / sizeof(builtin_themes[0]); + + // Try to open the theme config file to check for custom themes + FILE *config_file = fopen(theme_config_path, "r"); + char custom_theme[32]; + int has_custom_theme = 0; + + if (config_file) { + char theme_line[64]; + while (fgets(theme_line, sizeof(theme_line), config_file)) { + if (sscanf(theme_line, "theme=%31s", custom_theme) == 1) { + // Check if this is a custom theme (not one of our builtin themes) + int is_builtin = 0; + for (int i = 0; i < builtin_count; i++) { + if (strcmp(custom_theme, builtin_themes[i]) == 0) { + is_builtin = 1; + break; + } + } + + if (!is_builtin) { + has_custom_theme = 1; + break; + } + } + } + fclose(config_file); + } + + // Allocate space for themes (builtin + potential custom theme) + int total_themes = builtin_count + (has_custom_theme ? 1 : 0); + char **theme_names = (char **)malloc(total_themes * sizeof(char *)); + if (!theme_names) { + fprintf(stderr, "lsh: allocation error in get_theme_names\n"); + *theme_count = 0; + return NULL; + } + + // Copy builtin theme names + for (int i = 0; i < builtin_count; i++) { + theme_names[i] = strdup(builtin_themes[i]); + } + + // Add custom theme if found + if (has_custom_theme) { + theme_names[builtin_count] = strdup(custom_theme); + } + + *theme_count = total_themes; + return theme_names; +} diff --git a/themes.h b/themes.h new file mode 100644 index 0000000..c65bdf7 --- /dev/null +++ b/themes.h @@ -0,0 +1,92 @@ +#ifndef THEMES_H +#define THEMES_H + +#include "common.h" + +typedef struct { + // Standard console colors + WORD PRIMARY_COLOR; // Main text color + WORD SECONDARY_COLOR; // Secondary text color + WORD ACCENT_COLOR; // Color for highlights/important elements + WORD SUCCESS_COLOR; // Success messages + WORD ERROR_COLOR; // Error messages + WORD WARNING_COLOR; // Warning messages + + WORD INVALID_COMMAND_COLOR; // unrecognized command + + // UI element colors + WORD HEADER_COLOR; // Headers and titles + WORD STATUS_BAR_COLOR; // Status bar background + WORD STATUS_TEXT_COLOR; // Status bar text + WORD PROMPT_COLOR; // Command prompt + + // File system colors + WORD DIRECTORY_COLOR; // Directory names + WORD EXECUTABLE_COLOR; // Executable files + WORD TEXT_FILE_COLOR; // Text files + WORD IMAGE_FILE_COLOR; // Image files + WORD CODE_FILE_COLOR; // Code files (non-executable) + WORD ARCHIVE_FILE_COLOR; // Archive files + + // Syntax highlighting colors + WORD SYNTAX_KEYWORD; // Keywords in syntax highlighting + WORD SYNTAX_STRING; // Strings in syntax highlighting + WORD SYNTAX_COMMENT; // Comments in syntax highlighting + WORD SYNTAX_NUMBER; // Numbers in syntax highlighting + WORD SYNTAX_PREPROCESSOR; // Preprocessor in syntax highlighting + + // ANSI true color definitions (for modern terminals) + char ANSI_BASE[20]; // Base color + char ANSI_SURFACE[20]; // Surface color + char ANSI_OVERLAY[20]; // Overlay color + char ANSI_MUTED[20]; // Muted color + char ANSI_SUBTLE[20]; // Subtle color + char ANSI_TEXT[20]; // Text color + char ANSI_LOVE[20]; // Love/Red color + char ANSI_GOLD[20]; // Gold color + char ANSI_ROSE[20]; // Rose/pink color + char ANSI_PINE[20]; // Pine color + char ANSI_FOAM[20]; // Foam color + char ANSI_IRIS[20]; // Iris color + char ANSI_HIGHLIGHT[20]; // Highlight color + + char ANSI_INVALID_COMMAND[20]; + + // Flag to indicate if ANSI colors should be used + BOOL use_ansi_colors; + + // Name of the theme + char name[32]; +} ShellTheme; + +// Initialize theme system +void init_theme_system(void); + +// Shutdown theme system +void shutdown_themes(void); + +// Initialize themes for shell startup +void init_themes(void); + +// Load a theme by name +int load_theme(const char *theme_name); + +// Apply current theme settings +void apply_current_theme(void); + +// Get current theme +const ShellTheme *get_current_theme(void); + +// List available themes +void list_available_themes(void); + +// Get theme names for tab completion +char **get_theme_names(int *theme_count); + +// Command handler for "theme" command +int lsh_theme(char **args); + +// Current active theme +extern ShellTheme current_theme; + +#endif // THEMES_H \ No newline at end of file diff --git a/themes.o b/themes.o new file mode 100644 index 0000000000000000000000000000000000000000..2d4a79226351e46bb7e4480dd4829ead1c17e510 GIT binary patch literal 19616 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 Kh!wfU`Tqc_CgB + +/** + * Format a time interval in milliseconds to a readable string + * + * @param ms Time in milliseconds + * @param buffer Buffer to store formatted time + * @param buffer_size Size of the buffer + */ +void format_time(double ms, char *buffer, size_t buffer_size) { + if (ms < 1.0) { + // Microseconds + snprintf(buffer, buffer_size, "%.2f μs", ms * 1000); + } else if (ms < 1000.0) { + // Milliseconds + snprintf(buffer, buffer_size, "%.2f ms", ms); + } else if (ms < 60000.0) { + // Seconds + snprintf(buffer, buffer_size, "%.2f s", ms / 1000); + } else { + // Minutes and seconds + int minutes = (int)(ms / 60000); + double seconds = (ms - minutes * 60000) / 1000; + snprintf(buffer, buffer_size, "%d min %.2f s", minutes, seconds); + } +} + +/** + * Implementation of the timer command + * Usage: timer COMMAND [ARGS...] + * + * @param args Command arguments + * @return 1 to continue, 0 to exit + */ +int lsh_timer(char **args) { + if (!args[1]) { + printf("timer: usage: timer COMMAND [ARGS...]\n"); + printf("Measures execution time of a command\n"); + return 1; + } + + // Create a new array for the command to execute (without "timer" prefix) + char **cmd_args = &args[1]; + + // Start timing + clock_t start_time = clock(); + + // Execute the command + int result; + if (strcmp(cmd_args[0], "cd") == 0 || strcmp(cmd_args[0], "exit") == 0 || + strcmp(cmd_args[0], "timer") == 0) { + // Handle built-in commands that might affect shell state + printf("timer: can't time built-in command: %s\n", cmd_args[0]); + result = 1; + } else { + // Execute the command normally + result = lsh_execute(cmd_args); + } + + // End timing + clock_t end_time = clock(); + + // Calculate execution time in milliseconds + double execution_time_ms = + ((double)(end_time - start_time) / CLOCKS_PER_SEC) * 1000; + + // Format the execution time + char time_str[64]; + format_time(execution_time_ms, time_str, sizeof(time_str)); + + // Print the execution time with color + printf("\n"); + printf(ANSI_COLOR_GREEN); // Green text for highlighted display + printf("╭───────────────────────────────╮\n"); + printf("│ Execution time: %-14s │\n", time_str); + printf("╰───────────────────────────────╯\n"); + printf(ANSI_COLOR_RESET); // Reset color + + return result; +} + +/** + * Implementation of the time command (alias for timer) + * Usage: time COMMAND [ARGS...] + * + * @param args Command arguments + * @return 1 to continue, 0 to exit + */ +int lsh_time(char **args) { return lsh_timer(args); } \ No newline at end of file diff --git a/timer.h b/timer.h new file mode 100644 index 0000000..412c851 --- /dev/null +++ b/timer.h @@ -0,0 +1,38 @@ +/** + * timer.h + * Header for command execution timer functionality + */ + +#ifndef TIMER_H +#define TIMER_H + +#include "common.h" + +/** + * Format a time interval in milliseconds to a readable string + * + * @param ms Time in milliseconds + * @param buffer Buffer to store formatted time + * @param buffer_size Size of the buffer + */ +void format_time(double ms, char *buffer, size_t buffer_size); + +/** + * Implementation of the timer command + * Usage: timer COMMAND [ARGS...] + * + * @param args Command arguments + * @return 1 to continue, 0 to exit + */ +int lsh_timer(char **args); + +/** + * Implementation of the time command (alias for timer) + * Usage: time COMMAND [ARGS...] + * + * @param args Command arguments + * @return 1 to continue, 0 to exit + */ +int lsh_time(char **args); + +#endif // TIMER_H diff --git a/timer.o b/timer.o new file mode 100644 index 0000000000000000000000000000000000000000..8717e83f21efbd4b4a407127a2d840b1eef6a632 GIT binary patch literal 7776 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 KHcM-Rw*N1|-KR +#include +#include +#include + +/** + * Command handler for the "weather" command + * In this Linux version, we'll provide instructions for using curl/wget + */ +int lsh_weather(char **args) { + printf("\n"); + printf("╭─────────────────────────────────────────────────────────────╮\n"); + printf("│ Weather Command (Linux Version) │\n"); + printf("├─────────────────────────────────────────────────────────────┤\n"); + printf("│ This is a simplified version of the weather command for │\n"); + printf("│ Linux. The full version would use libcurl for HTTP requests. │\n"); + printf("│ │\n"); + printf("│ To get weather information on Linux: │\n"); + printf("│ │\n"); + printf("│ 1. Using curl: │\n"); + printf("│ curl wttr.in/[city] │\n"); + printf("│ │\n"); + printf("│ 2. Using wget: │\n"); + printf("│ wget -O - wttr.in/[city] │\n"); + printf("│ │\n"); + printf("│ For example: │\n"); + printf("│ curl wttr.in/London │\n"); + printf("│ curl wttr.in/\"New York\" │\n"); + printf("│ │\n"); + printf("│ For a shorter format: │\n"); + printf("│ curl wttr.in/London?format=3 │\n"); + printf("│ │\n"); + printf("├─────────────────────────────────────────────────────────────┤\n"); + + // Check if a city was provided as an argument + if (args[1]) { + char command[256]; + // Use wttr.in for a simple demonstration + snprintf(command, sizeof(command), "curl -s wttr.in/%s?format=3", args[1]); + printf("│ Running: %-47s │\n", command); + printf("├─────────────────────────────────────────────────────────────┤\n"); + printf("│ Result: │\n"); + printf("│ │\n"); + + // Execute the command + FILE *fp = popen(command, "r"); + if (fp) { + char buffer[256]; + if (fgets(buffer, sizeof(buffer), fp)) { + // Print the result with padding + printf("│ %-53s │\n", buffer); + } else { + printf("│ No result returned │\n"); + } + pclose(fp); + } else { + printf("│ Error executing command │\n"); + } + + printf("│ │\n"); + } + + printf("╰─────────────────────────────────────────────────────────────╯\n\n"); + + return 1; +} \ No newline at end of file diff --git a/weather.h b/weather.h new file mode 100644 index 0000000..dccd1d2 --- /dev/null +++ b/weather.h @@ -0,0 +1,8 @@ +#ifndef WEATHER_H +#define WEATHER_H + +#include "common.h" + +int lsh_weather(char **args); + +#endif // WEATHER_H diff --git a/weather.o b/weather.o new file mode 100644 index 0000000000000000000000000000000000000000..4b7d49d009cf3bccfdeec014a50d61487ea87149 GIT binary patch literal 10064 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

    ilJS)fiD(XL%RfV^$n3Qf;#gyS16U6 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 z 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%0D7{e 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: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