From aec8e482687dd4d74cc009706b352b0a69e8ed5f Mon Sep 17 00:00:00 2001 From: Michael Vetter Date: Thu, 26 Feb 2026 22:28:35 +0100 Subject: [PATCH] refactor: modernize cmd_ac_complete_filepath and simplify path handling --- src/command/cmd_ac.c | 100 ++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 59 deletions(-) diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c index 94c28309..9c3f8c4e 100644 --- a/src/command/cmd_ac.c +++ b/src/command/cmd_ac.c @@ -1653,60 +1653,49 @@ cmd_ac_uninit(void) } static void -_filepath_item_free(char** ptr) +_filepath_item_free(gchar** ptr) { - char* item = *ptr; - free(item); + gchar* item = *ptr; + g_free(item); } char* cmd_ac_complete_filepath(const char* const input, char* const startstr, gboolean previous) { - unsigned int output_off = 0; - char* tmp = NULL; - // strip command - char* inpcp = (char*)input + strlen(startstr); - while (*inpcp == ' ') { - inpcp++; + char* inpcp_ptr = (char*)input + strlen(startstr); + while (*inpcp_ptr == ' ') { + inpcp_ptr++; } - inpcp = strdup(inpcp); + auto_gchar gchar* inpcp = g_strdup(inpcp_ptr); // strip quotes - if (*inpcp == '"') { - tmp = strrchr(inpcp + 1, '"'); - if (tmp) { - *tmp = '\0'; + if (inpcp[0] == '"') { + char* last_quote = strrchr(inpcp + 1, '"'); + if (last_quote) { + *last_quote = '\0'; } - tmp = strdup(inpcp + 1); - free(inpcp); - inpcp = tmp; - tmp = NULL; + gchar* unquoted = g_strdup(inpcp + 1); + inpcp = unquoted; } - // expand ~ to $HOME - if (inpcp[0] == '~' && inpcp[1] == '/') { - char* home = getenv("HOME"); - if (!home) { - free(inpcp); - return NULL; - } - tmp = g_strdup_printf("%s/%sfoo", home, inpcp + 2); - output_off = strlen(home) + 1; - } else { - tmp = g_strdup_printf("%sfoo", inpcp); - } - free(inpcp); - if (!tmp) { + auto_gchar gchar* expanded = get_expanded_path(inpcp); + if (!expanded) { return NULL; } - char* foofile = strdup(basename(tmp)); - char* directory = strdup(dirname(tmp)); - g_free(tmp); + auto_gchar gchar* foofile = g_path_get_basename(expanded); + auto_gchar gchar* directory = g_path_get_dirname(expanded); - GArray* files = g_array_new(TRUE, FALSE, sizeof(char*)); + // If the input ends with a slash, the basename will be "." or "/" + // In that case, we are looking for all files in that directory + gboolean find_all = FALSE; + if (inpcp[strlen(inpcp) - 1] == '/') { + find_all = TRUE; + } + + GArray* files = g_array_new(TRUE, FALSE, sizeof(gchar*)); g_array_set_clear_func(files, (GDestroyNotify)_filepath_item_free); DIR* d = opendir(directory); @@ -1714,40 +1703,33 @@ cmd_ac_complete_filepath(const char* const input, char* const startstr, gboolean struct dirent* dir; while ((dir = readdir(d)) != NULL) { - if (strcmp(dir->d_name, ".") == 0) { - continue; - } else if (strcmp(dir->d_name, "..") == 0) { - continue; - } else if (*(dir->d_name) == '.' && *foofile != '.') { - // only show hidden files on explicit request + if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0) { continue; } - char* acstring = NULL; - if (output_off) { - tmp = g_strdup_printf("%s/%s", directory, dir->d_name); - if (tmp) { - acstring = g_strdup_printf("~/%s", tmp + output_off); - g_free(tmp); - } - } else if (strcmp(directory, "/") == 0) { + // check if it matches prefix + if (!find_all && !g_str_has_prefix(dir->d_name, foofile)) { + continue; + } + + // only show hidden files on explicit request + if (dir->d_name[0] == '.' && (find_all || foofile[0] != '.')) { + continue; + } + + auto_gchar gchar* acstring = NULL; + if (strcmp(directory, "/") == 0) { acstring = g_strdup_printf("/%s", dir->d_name); } else { acstring = g_strdup_printf("%s/%s", directory, dir->d_name); } - if (!acstring) { - g_array_free(files, TRUE); - free(foofile); - free(directory); - return NULL; - } - g_array_append_val(files, acstring); + if (acstring) { + g_array_append_val(files, acstring); + } } closedir(d); } - free(directory); - free(foofile); autocomplete_update(filepath_ac, (char**)files->data); g_array_free(files, TRUE);