refactor: modernize cmd_ac_complete_filepath and simplify path handling

This commit is contained in:
Michael Vetter
2026-02-26 22:28:35 +01:00
parent 65ca3c448b
commit aec8e48268

View File

@@ -1653,60 +1653,49 @@ cmd_ac_uninit(void)
} }
static void static void
_filepath_item_free(char** ptr) _filepath_item_free(gchar** ptr)
{ {
char* item = *ptr; gchar* item = *ptr;
free(item); g_free(item);
} }
char* char*
cmd_ac_complete_filepath(const char* const input, char* const startstr, gboolean previous) cmd_ac_complete_filepath(const char* const input, char* const startstr, gboolean previous)
{ {
unsigned int output_off = 0;
char* tmp = NULL;
// strip command // strip command
char* inpcp = (char*)input + strlen(startstr); char* inpcp_ptr = (char*)input + strlen(startstr);
while (*inpcp == ' ') { while (*inpcp_ptr == ' ') {
inpcp++; inpcp_ptr++;
} }
inpcp = strdup(inpcp); auto_gchar gchar* inpcp = g_strdup(inpcp_ptr);
// strip quotes // strip quotes
if (*inpcp == '"') { if (inpcp[0] == '"') {
tmp = strrchr(inpcp + 1, '"'); char* last_quote = strrchr(inpcp + 1, '"');
if (tmp) { if (last_quote) {
*tmp = '\0'; *last_quote = '\0';
} }
tmp = strdup(inpcp + 1); gchar* unquoted = g_strdup(inpcp + 1);
free(inpcp); inpcp = unquoted;
inpcp = tmp;
tmp = NULL;
} }
// expand ~ to $HOME auto_gchar gchar* expanded = get_expanded_path(inpcp);
if (inpcp[0] == '~' && inpcp[1] == '/') { if (!expanded) {
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) {
return NULL; return NULL;
} }
char* foofile = strdup(basename(tmp)); auto_gchar gchar* foofile = g_path_get_basename(expanded);
char* directory = strdup(dirname(tmp)); auto_gchar gchar* directory = g_path_get_dirname(expanded);
g_free(tmp);
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); g_array_set_clear_func(files, (GDestroyNotify)_filepath_item_free);
DIR* d = opendir(directory); DIR* d = opendir(directory);
@@ -1714,40 +1703,33 @@ cmd_ac_complete_filepath(const char* const input, char* const startstr, gboolean
struct dirent* dir; struct dirent* dir;
while ((dir = readdir(d)) != NULL) { while ((dir = readdir(d)) != NULL) {
if (strcmp(dir->d_name, ".") == 0) { if (strcmp(dir->d_name, ".") == 0 || 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
continue; continue;
} }
char* acstring = NULL; // check if it matches prefix
if (output_off) { if (!find_all && !g_str_has_prefix(dir->d_name, foofile)) {
tmp = g_strdup_printf("%s/%s", directory, dir->d_name); continue;
if (tmp) { }
acstring = g_strdup_printf("~/%s", tmp + output_off);
g_free(tmp); // only show hidden files on explicit request
} if (dir->d_name[0] == '.' && (find_all || foofile[0] != '.')) {
} else if (strcmp(directory, "/") == 0) { continue;
}
auto_gchar gchar* acstring = NULL;
if (strcmp(directory, "/") == 0) {
acstring = g_strdup_printf("/%s", dir->d_name); acstring = g_strdup_printf("/%s", dir->d_name);
} else { } else {
acstring = g_strdup_printf("%s/%s", directory, dir->d_name); 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); closedir(d);
} }
free(directory);
free(foofile);
autocomplete_update(filepath_ac, (char**)files->data); autocomplete_update(filepath_ac, (char**)files->data);
g_array_free(files, TRUE); g_array_free(files, TRUE);