aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlonkaars <loek@pipeframe.xyz>2024-05-24 15:18:44 +0200
committerlonkaars <loek@pipeframe.xyz>2024-05-24 15:18:44 +0200
commit31c30df2a24a45c69a7c5c2f594fa3a9a835b1fb (patch)
tree59d86bac0175a2f6001d0a54aa8f42e43b27d474
parentb74efcf6c6badcc7dc1937d511a163108f9fac0f (diff)
add tab completion + help function
-rw-r--r--client/cmd.cpp17
-rw-r--r--client/cmd.h45
-rw-r--r--client/rl.cpp20
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);