[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Lost] [PATCH] sh - tab-completion für beliebige Befehle



Anbei mein erster und wenig erfolgreicher Versuch, apps/sh beizubringen,
bei der tab-completion auch Programme in $PATH zu berücksichtigen.
Das Ganze macht noch nicht ganz was erwünscht ist, würde es auch nicht
wenn es funktionierte.
- Der Inhalt von $PATH wird atm nur einmalig beim Start von sh gelesen.
- Bei der Anzeige der zur Verfügung stehenden Befehle werden
augenscheinlich die ersten 2 Zeichen des nächsten Befehlsnamens durch
willkürliche ersetzt (?!)
Kritik und natürlich Hinweise sind immer willkommen.

kaffeefilter
Index: src/include/collections.h
===================================================================
--- src/include/collections.h	(Revision 923)
+++ src/include/collections.h	(Arbeitskopie)
@@ -12,6 +12,7 @@
 void list_destroy(list_t* list);
 list_t* list_push(list_t* list, void* value);
 void* list_pop(list_t* list);
+void list_merge_into(list_t* target, list_t* to_merge);
 bool list_is_empty(list_t* list);
 void* list_get_element_at(list_t* list, int index);
 list_t* list_insert(list_t* list, int index, void* value);
Index: src/lib/collections/list.c
===================================================================
--- src/lib/collections/list.c	(Revision 923)
+++ src/lib/collections/list.c	(Arbeitskopie)
@@ -163,7 +163,7 @@
     }
 
     return value;
-}
+}    
     
 /**
  * Gibt einen Knoten aus der Liste zur�ird von allen Funktionen benutzt,
@@ -212,6 +212,21 @@
 }
 
 /**
+ * Vereinigt zwei Listen, indem eine Liste in die Ziel-Liste
+ * eingefuegt wird und das Quell-Listenhandle zerstoert wird.
+ * @param target Ziel-Liste
+ * @param to_merge Quell-Liste
+ */
+void list_merge_into(list_t* target, list_t* to_merge)
+{
+    if ((!target) || (!to_merge)) return;
+    (list_get_node_at(to_merge, ((to_merge->size)-1)))->next = target->anchor;
+    target->anchor = to_merge->anchor;
+    target->size += to_merge->size;
+    free(to_merge);
+}
+
+/**
  * Fragt den Wert eines Listenelements ab.
  *
  * @param list Liste, deren Element abgefragt werden soll
Index: src/modules/c/shell/completion.c
===================================================================
--- src/modules/c/shell/completion.c	(Revision 923)
+++ src/modules/c/shell/completion.c	(Arbeitskopie)
@@ -44,6 +44,8 @@
 
 #include "shell.h"
 
+static list_t* executables_in_path;
+
 /**
  * Completion-Handler fuer Readline
  *
@@ -56,13 +58,23 @@
 /**
  * Matches in Befehlen suchen
  *
+ * @param word  Wort, das vervollstaendigt werden soll
  * @return Pointer auf Array oder NULL wenn keine Gefunden wurden
  */
 static char** shell_command_matches(const char* word);
 
 /**
+ * Matches in Befehlen suchen, die nicht in shell_commands[]
+ * vorhanden sind.
+ *
+ * @param word  Wort, das vervollstaendigt werden soll
+ * @return Pointer auf list_t oder NULL bei null Uebereinstimmungen
+ */
+static list_t* shell_executable_matches(const char* word);
+/**
  * Matches in Umgebungsvariabeln suchen
  *
+ * @param word  Wort, das vervollstaendigt werden soll
  * @return Pointer auf Array oder NULL wenn keine Gefunden wurden
  */
 static char** shell_envvar_matches(const char* word);
@@ -70,6 +82,7 @@
 /**
  * Matches in Dateien
  *
+ * @param word  Wort, das vervollstaendigt werden soll
  * @return Pointer auf Array oder NULL wenn keine Gefunden wurden
  */
 static char** shell_file_matches(const char* word);
@@ -84,6 +97,7 @@
  */
 void completion_init()
 {
+    update_path_env();
     rl_attempted_completion_function = rl_completion;
 }
 
@@ -110,6 +124,26 @@
     return matches;
 }
 
+void update_path_env(void)
+{
+    io_resource_t* dir;
+    io_direntry_t* dentry;
+    list_t* executables;
+    
+    const char* path = getenv("PATH");
+    if ((dir = directory_open(path)) == NULL) return;
+    executables = list_create();
+    while ((dentry = directory_read(dir))) {
+        if (dentry->type == IO_DIRENTRY_DIR) continue;
+        list_push(executables, strdup (dentry->name));
+    }
+    
+    list_destroy(executables_in_path);
+    executables_in_path = executables;
+}
+    
+    
+
 static char** build_matches_array(list_t* list)
 {
     char** matches;
@@ -152,6 +186,7 @@
         return NULL;
     }
 
+    list_merge_into(matches_list, shell_executable_matches(word));
     matches = build_matches_array(matches_list);
 
     list_destroy(matches_list);
@@ -159,6 +194,33 @@
     return matches;
 }
 
+static list_t* shell_executable_matches(const char* word)
+{
+    char* filename;
+    list_t* matches_list = list_create();
+    
+    int i;
+    for (i = 0; i < list_size(executables_in_path); i++) {
+        filename = list_get_element_at(executables_in_path, i);
+        if (strncmp(filename, word, strlen(word)) == 0) {
+            size_t fnamelen = strlen(filename);
+            char fname[fnamelen + 2];
+            strcpy(fname, filename);
+            
+            fname[fnamelen] = ' ', 0;
+            
+            list_push(matches_list, strdup(fname));
+        }
+    }
+
+    if (list_size(matches_list) == 0) {
+        list_destroy(matches_list);
+        return NULL;
+    }
+
+    return matches_list;
+}
+
 static char** shell_envvar_matches(const char* word)
 {
     int word_len = strlen(word);
Index: src/modules/c/shell/shell.h
===================================================================
--- src/modules/c/shell/shell.h	(Revision 923)
+++ src/modules/c/shell/shell.h	(Arbeitskopie)
@@ -48,6 +48,7 @@
 bool shell_script(const char* path);
 bool shell_match_command(const char* cmd, const char* cmdline);
 void completion_init(void);
+void update_path_env(void);
 
 int shell_command_default(int argc, char* argv[], const char* args);
 int shell_command_help(int argc, char* argv[], const char* args);