bios: add auto completion for commands
authorFranck Jullien <franck.jullien@gmail.com>
Wed, 29 Apr 2020 19:57:13 +0000 (21:57 +0200)
committerFranck Jullien <franck.jullien@gmail.com>
Fri, 1 May 2020 10:12:35 +0000 (12:12 +0200)
litex/soc/software/bios/Makefile
litex/soc/software/bios/command.h
litex/soc/software/bios/complete.c [new file with mode: 0644]
litex/soc/software/bios/complete.h [new file with mode: 0644]
litex/soc/software/bios/readline.c

index c80e0a13045e218293aa12383f8446b18a0dde56..4b8c6a51c1eb892b148921760e95cff5701b56b3 100755 (executable)
@@ -26,6 +26,12 @@ OBJECTS = isr.o                      \
          cmd_spi_flash.o       \
          cmd_usddrphy.o
 
+ifneq "$(or $(TERM_NO_COMPLETE),$(TERM_MINI))" ""
+CFLAGS += -DTERM_NO_COMPLETE
+else
+OBJECTS += complete.o
+endif
+
 ifdef TERM_NO_HIST
 CFLAGS += -DTERM_NO_HIST
 endif
index 2470438958be8a576ca53a9a5a34590ce5b35436..693d79825e6d4eb77308a055bbbf778ddb222624 100644 (file)
@@ -7,6 +7,8 @@
 
 #define MAX_PARAM      8
 
+#define HIST_DEPTH     10      /* Used in string list, complete.c */
+
 #define MISC_CMDS      0
 #define SYSTEM_CMDS    1
 #define CACHE_CMDS     2
diff --git a/litex/soc/software/bios/complete.c b/litex/soc/software/bios/complete.c
new file mode 100644 (file)
index 0000000..e428329
--- /dev/null
@@ -0,0 +1,174 @@
+// This file is Copyright (c) 2020 Franck Jullien <franck.jullien@gmail.com>
+//
+//     Largely inspired/copied from U-boot and Barebox projects wich are:
+//         Sascha Hauer, Pengutronix, <s.hauer@pengutronix.de>
+
+// License: BSD
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "readline.h"
+#include "helpers.h"
+#include "command.h"
+#include "complete.h"
+
+static int tab_pressed = 0;
+
+char sl[HIST_DEPTH][CMD_LINE_BUFFER_SIZE];
+int sl_idx = 0;
+
+char out[CMD_LINE_BUFFER_SIZE];
+
+static void string_list_init(void)
+{
+       int i;
+       for (i = 0; i < HIST_DEPTH; i++)
+               sl[i][0] = 0;
+}
+
+static int string_list_add(const char *string)
+{
+       int i;
+       for (i = 0; i < HIST_DEPTH; i++) {
+               if (sl[i][0] == 0) {
+                       strncpy(&sl[i][0], string, CMD_LINE_BUFFER_SIZE);
+                       return 0;
+               }
+       }
+       return -1;
+}
+
+static int string_list_empty(void)
+{
+       int i;
+       for (i = 0; i < HIST_DEPTH; i++)
+               if (sl[i][0] != 0)
+                       return 0;
+       return 1;
+}
+
+static int string_list_count(void)
+{
+       int i, count = 0;
+       for (i = 0; i < HIST_DEPTH; i++)
+               if (sl[i][0] != 0)
+                       count++;
+       return count;
+}
+
+static char *list_first_entry(void)
+{
+       int i;
+       for (i = 0; i < HIST_DEPTH; i++)
+               if (sl[i][0] != 0)
+                       return &sl[i][0];
+       return NULL;
+}
+
+static void string_list_print_by_column(void)
+{
+       int len = 0, num, i, j;
+
+       for (i = 0; i < HIST_DEPTH; i++) {
+               if (sl[i][0] != 0) {
+                       int l = strlen(&sl[i][0]) + 4;
+                       if (l > len)
+                               len = l;
+               }
+       }
+
+       if (!len)
+               return;
+
+       num = 80 / (len + 1);
+
+       for (j = 0; j < HIST_DEPTH; j++) {
+               if (sl[j][0] != 0) {
+                       if (!(++i % num))
+                               printf("%s\n", &sl[j][0]);
+                       else
+                               printf("%-*s", len, &sl[j][0]);
+               }
+       }
+       if (i % num)
+               printf("\n");
+}
+
+static void command_complete(char *instr)
+{
+       struct command_struct * const *cmd;
+
+       for (cmd = __bios_cmd_start; cmd != __bios_cmd_end; cmd++)
+               if (!strncmp(instr, (*cmd)->name, strlen(instr)))
+                       string_list_add((*cmd)->name);
+}
+
+int complete(char *instr, char **outstr)
+{
+       int pos;
+       char ch;
+       int changed;
+       int outpos = 0;
+       int reprint = 0;
+       char *first_entry;
+       char *entry;
+       int i;
+
+       string_list_init();
+       command_complete(instr);
+
+       pos = strlen(instr);
+
+       *outstr = "";
+       if (string_list_empty())
+               reprint = 0;
+       else
+       {
+               out[0] = 0;
+
+               first_entry = list_first_entry();
+
+               while (1) {
+                       entry = first_entry;
+                       ch = entry[pos];
+                       if (!ch)
+                               break;
+
+                       changed = 0;
+                       for (i = 0; i < HIST_DEPTH; i++) {
+                               if (sl[i][0] != 0) {
+                                       if (!sl[i][pos])
+                                               break;
+                                       if (ch != sl[i][pos]) {
+                                               changed = 1;
+                                               break;
+                                       }
+                               }
+                       }
+
+                       if (changed)
+                               break;
+                       out[outpos++] = ch;
+                       pos++;
+               }
+
+               if ((string_list_count() != 1) && !outpos && tab_pressed) {
+                       printf("\n");
+                       string_list_print_by_column();
+                       reprint = 1;
+                       tab_pressed = 0;
+               }
+
+               out[outpos++] = 0;
+               *outstr = out;
+
+               if (*out == 0)
+                       tab_pressed = 1;
+               else
+                       tab_pressed = 0;
+       }
+
+       return reprint;
+}
diff --git a/litex/soc/software/bios/complete.h b/litex/soc/software/bios/complete.h
new file mode 100644 (file)
index 0000000..b615df7
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __COMPLETE_H__
+#define __COMPLETE_H__
+
+int complete(char *instr, char **outstr);
+
+#endif
index 998ebc0eff4f9b64a9629da09f45e34a1254d4c1..48d8f1a6c31e46ca410e2a623e19bd2467fae7c5 100644 (file)
@@ -17,6 +17,7 @@
 #include <uart.h>
 
 #include "readline.h"
+#include "complete.h"
 
 #ifndef TERM_NO_HIST
 static int hist_max = 0;
@@ -191,6 +192,12 @@ int readline(char *buf, int len)
        int insert = 1;
        char ichar;
 
+#ifndef TERM_NO_COMPLETE
+       char tmp;
+       int reprint, i;
+       char *completestr;
+#endif
+
        while (1) {
 
                ichar = read_key();
@@ -200,6 +207,27 @@ int readline(char *buf, int len)
 
                switch (ichar) {
                case '\t':
+#ifndef TERM_NO_COMPLETE
+                       buf[eol_num] = 0;
+                       tmp = buf[num];
+
+                       buf[num] = 0;
+                       reprint = complete(buf, &completestr);
+                       buf[num] = tmp;
+
+                       if (reprint) {
+                               printf("%s%s", PROMPT, buf);
+
+                               if (tmp)
+                                       for (i = 0; i < eol_num - num; i++)
+                                               getcmd_putch(CTL_BACKSPACE);
+                       }
+
+                       i = 0;
+                       while (completestr[i])
+                               cread_add_char(completestr[i++], insert, &num,
+                                               &eol_num, buf, len);
+#endif
                        break;
 
                case KEY_HOME: