[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 4/4] Make readline completers a little more useful
From: |
John Darrington |
Subject: |
[PATCH 4/4] Make readline completers a little more useful |
Date: |
Thu, 14 Nov 2019 13:26:51 +0100 |
* src/pk-cmd.c (dot_cmds): Move to global scope.
* src/pk-editor.c (null_completion_function): New function.
* src/pk-file.c (close_completion_function): New function.
* src/pk-info.c (info_completion_function): New function.
* src/pk-set.c (set_completion_function): New function.
* src/pk-repl.c (poke_completion_function): New function,
(poke_getc): New function,
---
src/pk-cmd.c | 2 +-
src/pk-editor.c | 8 ++++-
src/pk-file.c | 53 +++++++++++++++++++++++++--
src/pk-info.c | 32 ++++++++++++++++-
src/pk-repl.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
src/pk-set.c | 35 +++++++++++++++++-
6 files changed, 230 insertions(+), 8 deletions(-)
diff --git a/src/pk-cmd.c b/src/pk-cmd.c
index 5ff247e..3e068f7 100644
--- a/src/pk-cmd.c
+++ b/src/pk-cmd.c
@@ -55,7 +55,7 @@ extern struct pk_cmd editor_cmd; /* pk-editor.c */
struct pk_cmd null_cmd =
{NULL, NULL, NULL, 0, NULL, NULL};
-static struct pk_cmd *dot_cmds[] =
+struct pk_cmd *dot_cmds[] =
{
&file_cmd,
&exit_cmd,
diff --git a/src/pk-editor.c b/src/pk-editor.c
index b4fe37c..bcc0d26 100644
--- a/src/pk-editor.c
+++ b/src/pk-editor.c
@@ -121,5 +121,11 @@ pk_cmd_editor (int argc, struct pk_cmd_arg argv[],
uint64_t uflags)
return 1;
}
+static char *
+null_completion_function (const char *x, int state)
+{
+ return NULL;
+}
+
struct pk_cmd editor_cmd =
- {"editor", "", "", 0, NULL, pk_cmd_editor, ".editor"};
+ {"editor", "", "", 0, NULL, pk_cmd_editor, ".editor",
null_completion_function};
diff --git a/src/pk-file.c b/src/pk-file.c
index 54e6524..385968b 100644
--- a/src/pk-file.c
+++ b/src/pk-file.c
@@ -22,11 +22,58 @@
#include <gettext.h>
#define _(str) dgettext (PACKAGE, str)
#include <errno.h>
+#include <readline.h>
#include "ios.h"
#include "poke.h"
#include "pk-cmd.h"
+static void
+count_io_spaces (ios io, void *data)
+{
+ int *i = (int *) data;
+ if (i == NULL)
+ return;
+ (*i)++;
+}
+
+static char *
+close_completion_function (const char *x, int state)
+{
+ static int idx = 0;
+ static int n_ids = 0;
+ if (state == 0)
+ {
+ idx = 0;
+ n_ids = 0;
+ ios_map (count_io_spaces, &n_ids);
+ }
+ else
+ ++idx;
+
+ int len = strlen (x);
+ while (1)
+ {
+ if (idx >= n_ids)
+ break;
+ char buf[16];
+ snprintf (buf, 16, "#%d", idx);
+
+ int match = strncmp (buf, x, len);
+ if (match != 0)
+ {
+ idx++;
+ continue;
+ }
+
+ return strdup (buf);
+ }
+
+ return NULL;
+}
+
+
+
static int
pk_cmd_file (int argc, struct pk_cmd_arg argv[], uint64_t uflags)
{
@@ -199,13 +246,13 @@ pk_cmd_load_file (int argc, struct pk_cmd_arg argv[],
uint64_t uflags)
}
struct pk_cmd file_cmd =
- {"file", "tf", "", 0, NULL, pk_cmd_file, "file (FILENAME|#ID)"};
+ {"file", "tf", "", 0, NULL, pk_cmd_file, "file (FILENAME|#ID)",
rl_filename_completion_function};
struct pk_cmd close_cmd =
- {"close", "?t", "", PK_CMD_F_REQ_IO, NULL, pk_cmd_close, "close [#ID]"};
+ {"close", "?t", "", PK_CMD_F_REQ_IO, NULL, pk_cmd_close, "close [#ID]",
close_completion_function};
struct pk_cmd info_files_cmd =
{"files", "", "", 0, NULL, pk_cmd_info_files, "info files"};
struct pk_cmd load_cmd =
- {"load", "f", "", 0, NULL, pk_cmd_load_file, "load FILENAME"};
+ {"load", "f", "", 0, NULL, pk_cmd_load_file, "load FILENAME",
rl_filename_completion_function};
diff --git a/src/pk-info.c b/src/pk-info.c
index b8e7f03..1c6fe0f 100644
--- a/src/pk-info.c
+++ b/src/pk-info.c
@@ -34,5 +34,35 @@ struct pk_cmd *info_cmds[] =
struct pk_trie *info_trie;
+static char *
+info_completion_function (const char *x, int state)
+{
+ static int idx = 0;
+ if (state == 0)
+ idx = 0;
+ else
+ ++idx;
+
+ size_t len = strlen (x);
+ while (1)
+ {
+ struct pk_cmd **c = info_cmds + idx;
+
+ if (*c == &null_cmd)
+ break;
+
+ if (0 != strncmp ((*c)->name, x, len))
+ {
+ idx++;
+ continue;
+ }
+ return strdup ((*c)->name);
+ }
+
+ return NULL;
+}
+
+
struct pk_cmd info_cmd =
- {"info", "", "", 0, &info_trie, NULL, "info (files|variable|type)"};
+ {"info", "", "", 0, &info_trie, NULL, "info (files|variable|function)",
+ info_completion_function};
diff --git a/src/pk-repl.c b/src/pk-repl.c
index a81e371..4f48507 100644
--- a/src/pk-repl.c
+++ b/src/pk-repl.c
@@ -35,6 +35,110 @@
#include <signal.h>
#include <unistd.h>
+extern struct pk_cmd *dot_cmds[];
+extern struct pk_cmd null_cmd;
+
+static char *
+poke_completion_function (const char *x, int state)
+{
+ static int idx = 0;
+ static struct pkl_ast_node_iter iter;
+ pkl_env env = pkl_get_env (poke_compiler);
+ if (state == 0)
+ {
+ pkl_env_iter_begin (env, &iter);
+ idx = 0;
+ }
+ else
+ {
+ if (pkl_env_iter_end (env, &iter))
+ idx++;
+ else
+ pkl_env_iter_next (env, &iter);
+ }
+
+ size_t len = strlen (x);
+
+ /* "Normal" commands. */
+ for (;;)
+ {
+ if (pkl_env_iter_end (env, &iter))
+ break;
+
+ pkl_ast_node decl_name = PKL_AST_DECL_NAME (iter.node);
+ const char *name = PKL_AST_IDENTIFIER_POINTER (decl_name);
+ if (0 != strncmp (name, x, len))
+ {
+ pkl_env_iter_next (env, &iter);
+ continue;
+ }
+ return strdup (name);
+ }
+
+ /* Dot commands */
+ for (;;)
+ {
+ struct pk_cmd **c = dot_cmds + idx;
+ if (*c == &null_cmd)
+ break;
+
+ char *name = xmalloc (strlen ( (*c)->name) + 1);
+ strcpy (name, ".");
+ strcat (name, (*c)->name);
+ if (0 != strncmp (name, x, len))
+ {
+ free (name);
+ idx++;
+ continue;
+ }
+ return name;
+ }
+
+ return NULL;
+}
+
+/* Readline's getc callback.
+ Use this function to update the completer which
+ should be used.
+*/
+static int
+poke_getc (FILE *stream)
+{
+ char *line_to_point = xmalloc (rl_point + 1);
+ int end = rl_point ? rl_point - 1 : 0;
+ strncpy (line_to_point, rl_line_buffer, end);
+ line_to_point[end] = '\0';
+
+ char *tok = strtok (line_to_point, "\t ");
+
+ if (rl_completion_entry_function == poke_completion_function)
+ {
+ if (tok != NULL)
+ {
+ struct pk_cmd **c;
+ for (c = dot_cmds; *c != &null_cmd; ++c)
+ {
+ if (0 == strcmp ((*c)->name, tok + 1))
+ {
+ if ((*c)->completer)
+ {
+ rl_completion_entry_function = (*c)->completer;
+ goto end;
+ }
+ }
+ }
+ }
+
+ rl_completion_entry_function = poke_completion_function;
+ }
+
+ end:
+ free (line_to_point);
+
+ return rl_getc (stream);
+}
+
+
static void
banner (void)
{
@@ -61,7 +165,7 @@ banner (void)
pk_puts ("\".\n");
free (help_hyperlink);
}
-#else
+#else
pk_puts (_("For help, type \".help\".\n"));
#endif
pk_puts (_("Type \".exit\" to leave the program.\n"));
@@ -108,6 +212,7 @@ pk_repl (void)
read_history (poke_history);
}
#endif
+ rl_getc_function = poke_getc;
while (!poke_exit_p)
{
@@ -115,6 +220,7 @@ pk_repl (void)
char *line;
pk_term_flush ();
+ rl_completion_entry_function = poke_completion_function;
line = readline ("(poke) ");
if (line == NULL)
{
diff --git a/src/pk-set.c b/src/pk-set.c
index 8dd07a5..6e88e0b 100644
--- a/src/pk-set.c
+++ b/src/pk-set.c
@@ -307,7 +307,40 @@ struct pk_cmd *set_cmds[] =
&null_cmd
};
+static char *
+set_completion_function (const char *x, int state)
+{
+ static int idx = 0;
+ if (state == 0)
+ idx = 0;
+ else
+ ++idx;
+
+ int len = strlen (x);
+ while (1)
+ {
+ struct pk_cmd **c = set_cmds + idx;
+
+ if (*c == &null_cmd)
+ break;
+
+ char *name = xmalloc (strlen ( (*c)->name) + 1);
+ strcpy (name, (*c)->name);
+
+ int match = strncmp (name, x, len);
+ if (match != 0)
+ {
+ free (name);
+ idx++;
+ continue;
+ }
+ return name;
+ }
+
+ return NULL;
+}
+
struct pk_trie *set_trie;
struct pk_cmd set_cmd =
- {"set", "", "", 0, &set_trie, NULL, "set PROPERTY"};
+ {"set", "", "", 0, &set_trie, NULL, "set PROPERTY", set_completion_function};
--
2.11.0