diff --git a/builtins.c b/builtins.c index 0acb3c0..0fbd3c4 100644 --- a/builtins.c +++ b/builtins.c @@ -722,12 +722,70 @@ int lsh_gg(char **args) { printf(" d - diff\n"); printf(" b - branch\n"); printf(" ch - checkout\n"); + printf(" o - open in GitHub browser\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], "b") == 0) { + system("git branch"); + } else if (strcmp(args[1], "o") == 0) { + // Get the remote URL + FILE *fp; + char remote_url[1024] = {0}; + fp = popen("git config --get remote.origin.url 2>/dev/null", "r"); + if (fp) { + fgets(remote_url, sizeof(remote_url), fp); + pclose(fp); + + // Trim trailing newline + char *newline = strchr(remote_url, '\n'); + if (newline) *newline = '\0'; + + if (strlen(remote_url) > 0) { + // Convert SSH URLs to HTTPS + char https_url[1024] = {0}; + if (strstr(remote_url, "git@github.com:")) { + // Convert ssh format (git@github.com:user/repo.git) to https + char *repo_path = strchr(remote_url, ':'); + if (repo_path) { + repo_path++; // Skip the colon + // Remove .git suffix if present + char *git_suffix = strstr(repo_path, ".git"); + if (git_suffix) *git_suffix = '\0'; + + sprintf(https_url, "https://github.com/%s", repo_path); + } + } else if (strstr(remote_url, "https://github.com/")) { + // Already HTTPS format + strcpy(https_url, remote_url); + // Remove .git suffix if present + char *git_suffix = strstr(https_url, ".git"); + if (git_suffix) *git_suffix = '\0'; + } + + if (strlen(https_url) > 0) { + // Open the URL in the default browser + char command[1100]; + // Use xdg-open on Linux + sprintf(command, "xdg-open %s >/dev/null 2>&1", https_url); + int result = system(command); + if (result == 0) { + printf("Opening %s in browser\n", https_url); + } else { + printf("Failed to open browser. URL: %s\n", https_url); + } + } else { + printf("Could not parse GitHub URL from: %s\n", remote_url); + } + } else { + printf("No remote URL found. Is this a Git repository with a GitHub remote?\n"); + } + } else { + printf("Not in a Git repository or no remote configured\n"); + } } else if (strcmp(args[1], "c") == 0) { if (args[2] != NULL) { char command[1024]; diff --git a/builtins.o b/builtins.o index c8b5afb..235df55 100644 Binary files a/builtins.o and b/builtins.o differ diff --git a/fzf_native.o b/fzf_native.o index 695dd29..ed1aa60 100644 Binary files a/fzf_native.o and b/fzf_native.o differ diff --git a/line_reader.c b/line_reader.c index 7f33066..b5f7538 100644 --- a/line_reader.c +++ b/line_reader.c @@ -462,21 +462,26 @@ void update_suggestions(const char *buffer, int position) { // If we have suggestions, use the first one if (suggestion_count > 0) { - has_suggestion = 1; - suggestion_index = 0; - - // Create the full suggestion string that would be accepted - 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); + // Skip showing "./" suggestions as they're often not useful + if (strcmp(suggestions[0], "./") == 0) { + has_suggestion = 0; } else { - // We're completing a command - strncpy(full_suggestion, suggestions[suggestion_index], sizeof(full_suggestion) - 1); + has_suggestion = 1; + suggestion_index = 0; + + // Create the full suggestion string that would be accepted + 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'; } - full_suggestion[sizeof(full_suggestion) - 1] = '\0'; } } @@ -639,16 +644,12 @@ void refresh_display(const char *prompt_buffer, const char *buffer, int position // Always clear any existing menu first clear_menu(); - // Always redraw the command line to ensure prompt is visible - printf("\r\033[K%s%s", prompt_buffer, buffer); - fflush(stdout); + // Always show inline suggestion - even in menu mode + display_inline_suggestion(prompt_buffer, buffer, position); if (menu_mode) { - // Show menu of options below the input line + // Also show menu of options below the input line display_menu(prompt_buffer, buffer, position); - } else { - // Show inline suggestion - display_inline_suggestion(prompt_buffer, buffer, position); } } @@ -765,9 +766,10 @@ char *lsh_read_line(void) { printf("\r\033[K%s%s", prompt_buffer, buffer); fflush(stdout); - // Update suggestions for new state - update_suggestions(buffer, position); - display_inline_suggestion(prompt_buffer, buffer, position); + // Don't immediately show a new suggestion after accepting one + // The user likely wants to execute the command first + // update_suggestions(buffer, position); + // display_inline_suggestion(prompt_buffer, buffer, position); } } else { // Not in menu mode: execute the command as is @@ -804,11 +806,48 @@ char *lsh_read_line(void) { // Already in menu mode: cycle to next suggestion if (suggestion_count > 0) { suggestion_index = (suggestion_index + 1) % suggestion_count; + + // Update full_suggestion with the newly selected suggestion + 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'; + refresh_display(prompt_buffer, buffer, position); } } else { - // Enter menu mode if we have suggestions - if (has_suggestion && suggestion_count > 0) { + // If there's only one suggestion, accept it directly + if (has_suggestion && suggestion_count == 1) { + // Update buffer with the single suggestion + if (prefix_start > 0) { + // We're completing an argument + char temp[LSH_RL_BUFSIZE]; + strncpy(temp, buffer, prefix_start); + temp[prefix_start] = '\0'; + strncat(temp, suggestions[suggestion_index], + LSH_RL_BUFSIZE - strlen(temp) - 1); + + strncpy(buffer, temp, bufsize - 1); + } else { + // We're completing a command + strncpy(buffer, suggestions[suggestion_index], bufsize - 1); + } + buffer[bufsize - 1] = '\0'; + position = strlen(buffer); + + // Redraw the line with accepted suggestion + printf("\r\033[K%s%s", prompt_buffer, buffer); + fflush(stdout); + } + // Otherwise enter menu mode if we have multiple suggestions + else if (has_suggestion && suggestion_count > 1) { menu_mode = 1; suggestion_index = 0; // Start with first suggestion refresh_display(prompt_buffer, buffer, position); @@ -818,12 +857,40 @@ char *lsh_read_line(void) { // In menu mode, up arrow goes to previous suggestion if (suggestion_count > 0) { suggestion_index = (suggestion_index + suggestion_count - 1) % suggestion_count; + + // Update full_suggestion with the newly selected suggestion + 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'; + refresh_display(prompt_buffer, buffer, position); } } else if (c == KEY_DOWN && menu_mode) { // In menu mode, down arrow goes to next suggestion if (suggestion_count > 0) { suggestion_index = (suggestion_index + 1) % suggestion_count; + + // Update full_suggestion with the newly selected suggestion + 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'; + refresh_display(prompt_buffer, buffer, position); } } else if (c == KEY_UP && !menu_mode) { diff --git a/line_reader.o b/line_reader.o index f304a2d..df5a834 100644 Binary files a/line_reader.o and b/line_reader.o differ diff --git a/shell b/shell index 42dd446..228fe9c 100755 Binary files a/shell and b/shell differ