poke-devel
[Top][All Lists]
Advanced

[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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]