diff --git a/src/launcher.c b/src/launcher.c index 97c3472..5f1ed19 100644 --- a/src/launcher.c +++ b/src/launcher.c @@ -34,6 +34,7 @@ #include static char *complete_on_command(char*, size_t); +static char *complete_on_files(char*, size_t); void launcher_execute(Launcher launcher) @@ -102,6 +103,13 @@ launcher_execute(Launcher launcher) my_guitar_gently_wheeps = 0; break; case XK_Tab: + /* + * completion + * if there is not space in buffer we + * complete the command using complete_on_command. + * Else we try to complete on filename using + * complete_on_files. + */ buf[pos] = '\0'; if (lastwastab) tabhits++; @@ -114,7 +122,11 @@ launcher_execute(Launcher launcher) if (pos) { - complete = complete_on_command(tmpbuf, tabhits); + if (strchr(tmpbuf, ' ')) + complete = complete_on_files(tmpbuf, tabhits); + else + complete = complete_on_command(tmpbuf, tabhits); + if (complete) { strcpy(buf, tmpbuf); @@ -185,6 +197,10 @@ uicb_launcher(uicb_t cmd) return; } +/* + * Just search command in PATH. + * Return the characters to complete the command. + */ static char * complete_on_command(char *start, size_t hits) { @@ -201,6 +217,7 @@ complete_on_command(char *start, size_t hits) path = _strdup(getenv("PATH")); dirname = strtok(path, ":"); + /* recursively open PATH */ while (dirname) { if ((dir = opendir(dirname))) @@ -225,3 +242,67 @@ complete_on_command(char *start, size_t hits) return ret; } +/* + * Complete a filename or directory name. + * works like complete_on_command. + */ +static char * +complete_on_files(char *start, size_t hits) +{ + char *ret = NULL; + char *p; + char *dirname = NULL; + DIR *dir; + struct dirent *content; + size_t count = 0; + + if (!start || hits <= 0 || !(p = strrchr(start, ' '))) + return NULL; + + /* + * Search the directory to open and set + * the beginning of file to complete on pointer 'p'. + */ + if (*(++p) == '\0' || !strrchr(p, '/')) + dir = opendir("."); + else + { + dirname = _strdup(p); + p = strrchr(dirname, '/'); + if (p != dirname) + { + *(p++) = '\0'; + dir = opendir(dirname); + } + else + { + dir = opendir("/"); + p++; + } + } + + if (dir) + { + while ((content = readdir(dir))) + { + if (!strcmp(content->d_name, ".") || !strcmp(content->d_name, "..")) + continue; + if (!strncmp(content->d_name, p, strlen(p)) && ++count == hits) + { + /* If it's a directory append '/' to the completion + * TODO : content type can be a link to a directory check that + */ + if (content->d_type == DT_DIR) + asprintf(&ret, "%s/", content->d_name + strlen(p)); + else + ret = _strdup(content->d_name + strlen(p)); + break; + } + } + closedir(dir); + } + + IFREE(dirname); + + return ret; +}