Fix regression in command name completion reported by John Darrington.
authorBen Pfaff <blp@gnu.org>
Wed, 28 Jun 2006 05:49:03 +0000 (05:49 +0000)
committerBen Pfaff <blp@gnu.org>
Wed, 28 Jun 2006 05:49:03 +0000 (05:49 +0000)
Now completion is again state-dependent and occurs only on the first
line of a command.

src/language/ChangeLog
src/language/command.c
src/language/command.h
src/language/data-io/ChangeLog
src/language/data-io/inpt-pgm.c
src/language/line-buffer.c
src/language/line-buffer.h
src/ui/terminal/ChangeLog
src/ui/terminal/main.c
src/ui/terminal/read-line.c
src/ui/terminal/read-line.h

index a3d3b20b79c9a448b8d8edccdbd97edb9aa675da..962a80a14c995c45f2ae6af833c35c1f54f8099e 100644 (file)
@@ -1,3 +1,30 @@
+Tue Jun 27 22:36:38 2006  Ben Pfaff  <blp@gnu.org>
+
+       Fix regression in command name completion reported by John
+       Darrington.  Now completion is again state-dependent and occurs
+       only on the first line of a command.
+       
+       * command.c (do_parse_command): Move reading the first token of
+       the command here, from execute_command and cmd_input_program.
+       Call set_completion_state and getl_set_prompt_style here.
+       (do_parse_command) Use in_correct_state instead of
+       verify_valid_command.
+       (verify_valid_command) Break into two new functions,
+       in_correct_state and report_state_mismatch.
+       (set_completion_state) New function.
+       (cmd_complete) New function.
+       [HAVE_READLINE] (pspp_attempted_completion_function) Removed.
+       [HAVE_READLINE] (command_generator) Removed.
+
+       * line-buffer.c: (struct getl_source) Change `interactive' member
+       signature to take enum getl_prompt_style instead of const char *.
+       (create_interactive_source) Ditto, for parameter type.
+       (getl_append_interactive) Ditto.
+       (read_line_from_source) Pass get_prompt_style() to interactive
+       function instead of get_prompt().
+       (get_prompt) Removed.
+       (get_prompt_style) New function.
+       
 Sat May  6 13:25:25 2006  Ben Pfaff  <blp@gnu.org>
 
        Continue reforming procedure execution.  In this phase, remove
index ed043d2197363fc0ef81cebae2f119f480573ad1..c55ff1b8c6a1d542d076a81e2ed97f28fc1a7849 100644 (file)
@@ -32,6 +32,7 @@
 #include <data/settings.h>
 #include <data/variable.h>
 #include <language/lexer/lexer.h>
+#include <language/line-buffer.h>
 #include <libpspp/alloc.h>
 #include <libpspp/compiler.h>
 #include <libpspp/message.h>
@@ -120,8 +121,10 @@ static const struct command commands[] =
 
 static const size_t command_cnt = sizeof commands / sizeof *commands;
 
-static bool verify_valid_command (const struct command *, enum cmd_state);
+static bool in_correct_state (const struct command *, enum cmd_state);
+static bool report_state_mismatch (const struct command *, enum cmd_state);
 static const struct command *find_command (const char *name);
+static void set_completion_state (enum cmd_state); 
 \f
 /* Command parser. */
 
@@ -156,9 +159,18 @@ do_parse_command (enum cmd_state state)
   const struct command *command;
   enum cmd_result result;
 
-  /* Null commands can result from extra empty lines. */
-  if (token == '.')
-    return CMD_SUCCESS;
+  /* Read the command's first token. */
+  getl_set_prompt_style (GETL_PROMPT_FIRST);
+  set_completion_state (state);
+  lex_get ();
+  if (token == T_STOP)
+    return CMD_EOF;
+  else if (token == '.') 
+    {
+      /* Null commands can result from extra empty lines. */
+      return CMD_SUCCESS; 
+    }
+  getl_set_prompt_style (GETL_PROMPT_LATER);
 
   /* Parse the command name. */
   command = parse_command_name ();
@@ -177,8 +189,11 @@ do_parse_command (enum cmd_state state)
            command->name);
        return CMD_FAILURE;
     }
-  else if (!verify_valid_command (command, state))
-    return CMD_FAILURE;
+  else if (!in_correct_state (command, state)) 
+    {
+      report_state_mismatch (command, state);
+      return CMD_FAILURE; 
+    }
 
   /* Execute command. */
   msg_set_command_name (command->name);
@@ -539,19 +554,23 @@ parse_command_name (void)
 }
 
 /* Returns true if COMMAND is allowed in STATE,
-   false otherwise.
-   If COMMAND is not allowed, emits an appropriate error
-   message. */
+   false otherwise. */
 static bool
-verify_valid_command (const struct command *command, enum cmd_state state)
+in_correct_state (const struct command *command, enum cmd_state state) 
 {
-  if ((state == CMD_STATE_INITIAL && command->states & S_INITIAL)
-      || (state == CMD_STATE_DATA && command->states & S_DATA)
-      || (state == CMD_STATE_INPUT_PROGRAM
-          && command->states & S_INPUT_PROGRAM)
-      || (state == CMD_STATE_FILE_TYPE && command->states & S_FILE_TYPE))
-    return true;
+  return ((state == CMD_STATE_INITIAL && command->states & S_INITIAL)
+          || (state == CMD_STATE_DATA && command->states & S_DATA)
+          || (state == CMD_STATE_INPUT_PROGRAM
+              && command->states & S_INPUT_PROGRAM)
+          || (state == CMD_STATE_FILE_TYPE && command->states & S_FILE_TYPE));
+}
 
+/* Emits an appropriate error message for trying to invoke
+   COMMAND in STATE. */
+static bool
+report_state_mismatch (const struct command *command, enum cmd_state state)
+{
+  assert (!in_correct_state (command, state));
   if (state == CMD_STATE_INITIAL || state == CMD_STATE_DATA)
     {
       const char *allowed[3];
@@ -589,51 +608,36 @@ verify_valid_command (const struct command *command, enum cmd_state state)
   return false;
 }
 \f
-/* Readline command name completion. */
+/* Command name completion. */
 
-#if HAVE_READLINE
-static char *command_generator (const char *text, int state);
-
-/* Returns a set of completions for TEXT.
-   This is of the proper form for assigning to
-   rl_attempted_completion_function. */
-char **
-pspp_attempted_completion_function (const char *text,
-                                    int start, int end UNUSED)
+static enum cmd_state completion_state = CMD_STATE_INITIAL;
+
+static void
+set_completion_state (enum cmd_state state) 
 {
-  if (start == 0) 
-    {
-      /* Complete command name at start of line. */
-      return rl_completion_matches (text, command_generator); 
-    }
-  else 
-    {
-      /* Otherwise don't do any completion. */
-      rl_attempted_completion_over = 1;
-      return NULL; 
-    }
+  completion_state = state;
 }
 
-/* If STATE is 0, returns the first command name matching TEXT.
-   Otherwise, returns the next command name matching TEXT.
-   Returns a null pointer when no matches are left. */
-static char *
-command_generator (const char *text, int state) 
+/* Returns the next possible completion of a command name that
+   begins with PREFIX, in the current command state, or a null
+   pointer if no completions remain.
+   Before calling the first time, set *CMD to a null pointer. */
+const char *
+cmd_complete (const char *prefix, const struct command **cmd)
 {
-  static const struct command *cmd;
-  
-  if (!state)
-    cmd = commands;
+  if (*cmd == NULL)
+    *cmd = commands;
 
-  for (; cmd < commands + command_cnt; cmd++) 
-    if (!memcasecmp (cmd->name, text, strlen (text))
-        && (!(cmd->flags & F_TESTING) || get_testing_mode ())
-        && (!(cmd->flags & F_ENHANCED) || get_syntax () == ENHANCED))
-      return xstrdup (cmd++->name);
+  for (; *cmd < commands + command_cnt; (*cmd)++) 
+    if (!memcasecmp ((*cmd)->name, prefix, strlen (prefix))
+        && (!((*cmd)->flags & F_TESTING) || get_testing_mode ())
+        && (!((*cmd)->flags & F_ENHANCED) || get_syntax () == ENHANCED)
+        && ((*cmd)->function != NULL)
+        && in_correct_state (*cmd, completion_state))
+      return (*cmd)++->name;
 
   return NULL;
 }
-#endif /* HAVE_READLINE */
 \f
 /* Simple commands. */
 
index ec51f658689861494a1b94130d91825c73edac3c..3cf5b997bdfd06b14a58cfb44a18ea74e7d62af8 100644 (file)
@@ -54,12 +54,11 @@ enum cmd_state
     CMD_STATE_FILE_TYPE         /* Inside FILE TYPE. */
   };
 
-#if HAVE_READLINE
-char **pspp_attempted_completion_function (const char *, int start, int end);
-#endif
-
 enum cmd_result cmd_parse (enum cmd_state);
 
+struct command;
+const char *cmd_complete (const char *, const struct command **);
+
 /* Prototype all the command functions. */
 #define DEF_CMD(STATES, FLAGS, NAME, FUNCTION) int FUNCTION (void);
 #define UNIMPL_CMD(NAME, DESCRIPTION)
index 31e809e54650201aa535608fea7ce1b782a5c5e5..37047d67f6713a389e2e47aa174105858fcf3529 100644 (file)
@@ -1,3 +1,12 @@
+Tue Jun 27 22:44:28 2006  Ben Pfaff  <blp@gnu.org>
+
+       Fix regression in command name completion reported by John
+       Darrington.  Now completion is again state-dependent and occurs
+       only on the first line of a command.
+       
+       * inpt-pgm.c: (cmd_input_program) Reading of first token in
+       command moved into cmd_parse.
+
 Fri Jun  9 13:56:00 2006  Ben Pfaff  <blp@gnu.org>
 
        Reform string library.
index 51c369810f9d2872810a00341a0623321f4f04c8..94fa4044b291cb1c86997319c413665222d2bf7d 100644 (file)
@@ -119,9 +119,7 @@ cmd_input_program (void)
   inside_input_program = true;
   for (;;) 
     {
-      enum cmd_result result;
-      lex_get ();
-      result = cmd_parse (CMD_STATE_INPUT_PROGRAM);
+      enum cmd_result result = cmd_parse (CMD_STATE_INPUT_PROGRAM);
       if (result == CMD_END_INPUT_PROGRAM)
         break;
       else if (result == CMD_END_CASE) 
index 1b48f5386e26457bf95bcc797e5458d1ffb96429..96ef8559a0e63dbe47f449270a02629fff87d587 100644 (file)
@@ -85,7 +85,7 @@ struct getl_source
         function;
 
         /* INTERACTIVE. */
-        bool (*interactive) (struct string *line, const char *prompt);
+        bool (*interactive) (struct string *line, enum getl_prompt_style);
       }
     u;
 
@@ -103,7 +103,7 @@ static void close_source (void);
 
 static void init_prompts (void);
 static void uninit_prompts (void);
-static const char *get_prompt (void);
+static enum getl_prompt_style get_prompt_style (void);
 
 /* Initialize getl. */
 void
@@ -214,7 +214,7 @@ create_function_source (bool (*read) (struct string *line,
 /* Creates an interactive source with the given FUNCTION. */
 static struct getl_source *
 create_interactive_source (bool (*function) (struct string *line,
-                                             const char *prompt)) 
+                                             enum getl_prompt_style)) 
 {
   struct getl_source *s = xmalloc (sizeof *s);
   s->fn = NULL;
@@ -297,7 +297,7 @@ getl_include_function (bool (*read) (struct string *line,
    obtained or false at end of file. */
 void
 getl_append_interactive (bool (*function) (struct string *line,
-                                           const char *prompt)) 
+                                           enum getl_prompt_style)) 
 {
   append_source (create_interactive_source (function));
 }
@@ -489,7 +489,7 @@ read_line_from_source (struct string *line, struct getl_source *s)
     case FUNCTION:
       return s->u.function.read (line, &s->fn, &s->ln, s->u.function.aux);
     case INTERACTIVE:
-      return s->u.interactive (line, get_prompt ());
+      return s->u.interactive (line, get_prompt_style ());
     }
 
   abort ();
@@ -589,8 +589,8 @@ getl_set_prompt_style (enum getl_prompt_style style)
 }
 
 /* Returns the current prompt. */
-static const char *
-get_prompt (void) 
+static enum getl_prompt_style
+get_prompt_style (void) 
 {
-  return prompts[current_style];
+  return current_style;
 }
index 59dab0a58d830f35e1272339579ed699f9a96646..b47a2ce370e1d000e61c1f05f20c6da21558d02f 100644 (file)
 #include <stdbool.h>
 #include <libpspp/str.h>
 
+enum getl_prompt_style
+  {
+    GETL_PROMPT_FIRST,         /* First line of command. */
+    GETL_PROMPT_LATER,          /* Second or later line of command. */
+    GETL_PROMPT_DATA,          /* Between BEGIN DATA and END DATA. */
+    GETL_PROMPT_CNT
+  };
+
 /* Current line.  This line may be modified by modules other than
    getl.c, and by lexer.c in particular.  (Ugh.) */
 extern struct string getl_buf;
@@ -43,23 +51,13 @@ void getl_include_function (bool (*read) (struct string *line,
                             void (*close) (void *aux),
                             void *aux);
 void getl_append_interactive (bool (*function) (struct string *line,
-                                                const char *prompt));
+                                                enum getl_prompt_style));
 void getl_abort_noninteractive (void);
 bool getl_is_interactive (void);
 
 bool getl_read_line (bool *interactive);
 
 void getl_location (const char **, int *);
-\f
-/* Prompting. */
-
-enum getl_prompt_style
-  {
-    GETL_PROMPT_FIRST,         /* First line of command. */
-    GETL_PROMPT_LATER,           /* Second or later line of command. */
-    GETL_PROMPT_DATA,          /* Between BEGIN DATA and END DATA. */
-    GETL_PROMPT_CNT
-  };
 
 const char *getl_get_prompt (enum getl_prompt_style);
 void getl_set_prompt (enum getl_prompt_style, const char *);
index 00cef0f79459527b4e61bb2077af79f803df4037..039ac64460916ae31328606c1aea22603ff5375e 100644 (file)
@@ -1,3 +1,22 @@
+Tue Jun 27 22:44:56 2006  Ben Pfaff  <blp@gnu.org>
+
+       Fix regression in command name completion reported by John
+       Darrington.  Now completion is again state-dependent and occurs
+       only on the first line of a command.
+       
+       * main.c (main): Reading of first token in command moved into
+       cmd_parse.
+       (execute_command) Removed.
+
+       * read-line.c: [HAVE_READLINE] (readln_initialize) Postpone
+       setting rl_attempted_completion_function until readln_read.
+       [HAVE_READLINE] (readln_read) Change param from const char * to
+       enum getl_prompt_style.  Set rl_attempted_completion_function
+       based on style.
+       [HAVE_READLINE] (complete_command_name) New function.
+       [HAVE_READLINE] (dont_complete) New function.
+       [HAVE_READLINE] (command_generator) New function.
+
 Tue Jun 27 08:23:07 2006  Ben Pfaff  <blp@gnu.org>
 
        * automake.mk (src_ui_terminal_pspp_LDADD): Add $(LIBICONV).
index e19dd0c7a5eac5239aa9161a2f9380387d29fd7a..2ad53d36d4e4e3da16dea2580ed41c1c439933a7 100644 (file)
@@ -62,7 +62,6 @@
 
 static void i18n_init (void);
 static void fpu_init (void);
-static int execute_command (void);
 static void terminate (bool success) NO_RETURN;
 
 /* If a segfault happens, issue a message to that effect and halt */
@@ -102,7 +101,8 @@ main (int argc, char **argv)
 
       for (;;)
         {
-          int result = execute_command ();
+          int result = cmd_parse (proc_has_source ()
+                                  ? CMD_STATE_DATA : CMD_STATE_INITIAL);
           if (result == CMD_EOF || result == CMD_FINISH)
             break;
           if (result == CMD_CASCADING_FAILURE && !getl_is_interactive ())
@@ -118,25 +118,6 @@ main (int argc, char **argv)
   
   terminate (!any_errors ());
 }
-
-/* Parses a command and returns the result. */
-static int
-execute_command (void)
-{
-  /* Read the command's first token.  
-     The first token is part of the first line of the command. */
-  getl_set_prompt_style (GETL_PROMPT_FIRST);
-  lex_get ();
-  if (token == T_STOP)
-    return CMD_EOF;
-
-  /* Parse the command.
-     Any lines read after the first token must be continuation
-     lines. */
-  getl_set_prompt_style (GETL_PROMPT_LATER);
-  return cmd_parse (proc_has_source ()
-                    ? CMD_STATE_DATA : CMD_STATE_INITIAL);
-}
 \f
 static void
 i18n_init (void) 
index a87adfcf7ef8eacda1ce785abb6ccdf6ed57bb1e..08f9362355d7ddb8df9d81d807949d592ebfe975 100644 (file)
 #include <libpspp/version.h>
 #include <output/table.h>
 
+#include "xalloc.h"
+
 #include "gettext.h"
 #define _(msgid) gettext (msgid)
 
-
 #if HAVE_READLINE
 #include <readline/readline.h>
 #include <readline/history.h>
 
 static char *history_file;
+
+static char **complete_command_name (const char *, int, int);
+static char **dont_complete (const char *, int, int);
 #endif /* HAVE_READLINE */
 
 static bool initialised = false;
@@ -58,7 +62,6 @@ readln_initialize (void)
 
 #if HAVE_READLINE
   rl_basic_word_break_characters = "\n";
-  rl_attempted_completion_function = pspp_attempted_completion_function;
 #ifdef unix
   if (history_file == NULL)
     {
@@ -113,19 +116,23 @@ welcome (void)
    Returns true if successful, false at end of file.
    Suitable for passing to getl_append_interactive(). */
 bool
-readln_read (struct string *line, const char *prompt)
+readln_read (struct string *line, enum getl_prompt_style style)
 {
+  const char *prompt = getl_get_prompt (style);
 #if HAVE_READLINE
   char *string;
 #endif
   
-  assert(initialised);
+  assert (initialised);
 
   reset_msg_count ();
 
   welcome ();
 
 #if HAVE_READLINE
+  rl_attempted_completion_function = (style == GETL_PROMPT_FIRST
+                                      ? complete_command_name
+                                      : dont_complete);
   string = readline (prompt);
   if (string == NULL)
     return false;
@@ -149,3 +156,49 @@ readln_read (struct string *line, const char *prompt)
     return false;
 #endif
 }
+
+#ifdef HAVE_READLINE
+static char *command_generator (const char *text, int state);
+
+/* Returns a set of command name completions for TEXT.
+   This is of the proper form for assigning to
+   rl_attempted_completion_function. */
+static char **
+complete_command_name (const char *text, int start, int end UNUSED)
+{
+  if (start == 0) 
+    {
+      /* Complete command name at start of line. */
+      return rl_completion_matches (text, command_generator); 
+    }
+  else 
+    {
+      /* Otherwise don't do any completion. */
+      rl_attempted_completion_over = 1;
+      return NULL; 
+    }
+}
+
+/* Do not do any completion for TEXT. */
+static char **
+dont_complete (const char *text UNUSED, int start UNUSED, int end UNUSED)
+{
+  rl_attempted_completion_over = 1;
+  return NULL; 
+}
+
+/* If STATE is 0, returns the first command name matching TEXT.
+   Otherwise, returns the next command name matching TEXT.
+   Returns a null pointer when no matches are left. */
+static char *
+command_generator (const char *text, int state) 
+{ 
+  static const struct command *cmd;
+  const char *name;
+
+  if (state == 0)
+    cmd = NULL;
+  name = cmd_complete (text, &cmd);
+  return name ? xstrdup (name) : NULL;
+}
+#endif /* HAVE_READLINE */
index cadd2cce1410e9f130d07840364c5d1e7f0eeed4..9d490fc9eb930d456847b0316bd752194250bb35 100644 (file)
 #define READLN_H
 
 #include <libpspp/str.h>
+#include <language/line-buffer.h>
 
 void readln_initialize (void);
 void readln_uninitialize (void);
-bool readln_read (struct string *line, const char *prompt);
+bool readln_read (struct string *line, enum getl_prompt_style);
 
 #endif /* READLN_H */