diff options
author | lonkaars <loek@pipeframe.xyz> | 2024-05-24 15:18:44 +0200 |
---|---|---|
committer | lonkaars <loek@pipeframe.xyz> | 2024-05-24 15:18:44 +0200 |
commit | 31c30df2a24a45c69a7c5c2f594fa3a9a835b1fb (patch) | |
tree | 59d86bac0175a2f6001d0a54aa8f42e43b27d474 | |
parent | b74efcf6c6badcc7dc1937d511a163108f9fac0f (diff) |
add tab completion + help function
-rw-r--r-- | client/cmd.cpp | 17 | ||||
-rw-r--r-- | client/cmd.h | 45 | ||||
-rw-r--r-- | client/rl.cpp | 20 |
3 files changed, 77 insertions, 5 deletions
diff --git a/client/cmd.cpp b/client/cmd.cpp index 99a4dd6..0a73dad 100644 --- a/client/cmd.cpp +++ b/client/cmd.cpp @@ -1,3 +1,4 @@ +#include <cstdio> #include <cstdlib> #include <string.h> @@ -13,3 +14,19 @@ void cmd_test(char*) { i2c_send(0x39, (char*) data, strlen(data)); } +void cmd_help(char*) { + printf("List of available commands:\n"); + for (size_t i = 0; i < cmds_length; i++) { + struct cmd cmd = cmds[i]; + printf(" %-*s", 10, cmd.name); + if (cmd.info != NULL) + printf(" %s", cmd.info); + printf("\n"); + } + + printf( + "\n" + "You can also use the TAB key to autocomplete commands\n" + ); +} + diff --git a/client/cmd.h b/client/cmd.h index 509104a..7ec67fc 100644 --- a/client/cmd.h +++ b/client/cmd.h @@ -5,19 +5,56 @@ typedef void cmd_fn_t(char *); struct cmd { - const char* name; void (* handle)(char *); + const char* name; const char* info; // TODO: tab completion function? }; cmd_fn_t cmd_exit; cmd_fn_t cmd_test; +cmd_fn_t cmd_help; +cmd_fn_t cmd_send; +cmd_fn_t cmd_status; +cmd_fn_t cmd_reset; +cmd_fn_t cmd_ls; static const struct cmd cmds[] = { - (struct cmd){ .name = "exit", .handle = cmd_exit, .info = NULL, }, - (struct cmd){ .name = "test", .handle = cmd_test, .info = NULL, }, + { + .handle = cmd_exit, + .name = "exit", + .info = "exit pbc", + }, + { + .handle = cmd_test, + .name = "test", + .info = "send a test puzbus message", + }, + { + .handle = cmd_help, + .name = "help", + .info = "show this help", + }, + // { + // .handle = cmd_send, + // .name = "send", + // .info = "[debug] send raw message", + // }, + // { + // .handle = cmd_status, + // .name = "status", + // .info = "show global puzzle box state (main controller state)", + // }, + // { + // .handle = cmd_reset, + // .name = "reset", + // .info = "reset entire game state", + // }, + // { + // .handle = cmd_ls, + // .name = "ls", + // .info = "list connected puzzle modules", + // }, }; - static const size_t cmds_length = sizeof(cmds) / sizeof(cmds[0]); diff --git a/client/rl.cpp b/client/rl.cpp index b016370..6073500 100644 --- a/client/rl.cpp +++ b/client/rl.cpp @@ -37,16 +37,34 @@ void rl_printf(const char *fmt, ...) { } static bool cli_cmd(char* line) { + char* cmd = strtok(line, " \t\n"); for (size_t i = 0; i < cmds_length; i++) { - if (strcmp(line, cmds[i].name) != 0) continue; + if (strncmp(cmds[i].name, cmd, strlen(cmd)) != 0) continue; cmds[i].handle(line); return true; } return false; } +static char* rl_completion_entries(const char *text, int state) { + static size_t i = 0; + if (state == 0) i = 0; + + while (i < cmds_length) { + struct cmd cmd = cmds[i]; + i++; + if (strncmp(text, cmd.name, strlen(text)) == 0) { + return strdup(cmd.name); + } + } + + return NULL; +} + int cli_main() { char* input = NULL; + rl_completion_entry_function = rl_completion_entries; + while (1) { if (input != NULL) free(input); input = readline(CLI_PROMPT); |