+    printf("\r\n");
+}
+
+#define CLI_COMPLETE_COMMAND 1
+#define CLI_COMPLETE_GROUP 2
+
+typedef struct {
+    char *name;
+    int type;
+} completionEntry;
+
+static completionEntry *completionEntries;
+static int completionEntriesLen;
+
+/* Build 2 different arrays for completion. One for raw command completion and one
+ * for completion using HELP (including groups). */
+static void cliInitHelp() {
+    int commandslen = sizeof(commandHelp)/sizeof(struct commandHelp);
+    int groupslen = sizeof(commandGroups)/sizeof(char*);
+    int i, len, pos = 0;
+    completionEntry tmp;
+
+    completionEntriesLen = len = commandslen+groupslen;
+    completionEntries = malloc(sizeof(completionEntry)*len);
+
+    for (i = 0; i < groupslen; i++) {
+        tmp.name = malloc(strlen(commandGroups[i]+2));
+        sprintf(tmp.name,"@%s",commandGroups[i]);
+        tmp.type = CLI_COMPLETE_GROUP;
+        completionEntries[pos++] = tmp;
+    }
+
+    for (i = 0; i < commandslen; i++) {
+        tmp.name = commandHelp[i].name;
+        tmp.type = CLI_COMPLETE_COMMAND;
+        completionEntries[pos++] = tmp;
+    }
+}
+
+static void completionCallback(const char *buf, linenoiseCompletions *lc) {
+    size_t startpos = 0;
+    int mask;
+    int i;
+    size_t matchlen;
+    char *tmp;
+    size_t tmpsize;
+
+    if (strncasecmp(buf,"help ",5) == 0) {
+        startpos = 5;
+        while (isspace(buf[startpos])) startpos++;
+        mask = CLI_COMPLETE_COMMAND | CLI_COMPLETE_GROUP;
+    } else {
+        mask = CLI_COMPLETE_COMMAND;
+    }
+
+    for (i = 0; i < completionEntriesLen; i++) {
+        if (!(completionEntries[i].type & mask)) continue;
+
+        matchlen = strlen(buf+startpos);
+        if (strncasecmp(buf+startpos,completionEntries[i].name,matchlen) == 0) {
+            tmpsize = startpos+strlen(completionEntries[i].name)+1;
+            tmp = malloc(tmpsize);
+            memcpy(tmp,buf,startpos);
+            memcpy(tmp+startpos,completionEntries[i].name,tmpsize-startpos);
+            linenoiseAddCompletion(lc,tmp);
+            free(tmp);
+        }
+    }