Browse Source

Launcher: add filename completion

Philippe Pepiot 14 years ago
parent
commit
6abac69d8f
1 changed files with 82 additions and 1 deletions
  1. 82 1
      src/launcher.c

+ 82 - 1
src/launcher.c

@@ -34,6 +34,7 @@
 #include <dirent.h>
 
 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;
+}