[m-rev.] for review: mdb command line completion

Simon Taylor stayl at cs.mu.OZ.AU
Wed Mar 6 21:47:22 AEDT 2002


On 04-Mar-2002, Fergus Henderson <fjh at cs.mu.OZ.AU> wrote:
> On 04-Mar-2002, Simon Taylor <stayl at cs.mu.OZ.AU> wrote:
> > 
> > Add support for command line completion to mdb.
> 
> One thing I noticed is that there are no test cases.
> 
> I know we have had some issues with different versions of readline
> behaving differently, but even if we can't easily get the tests to work
> on all our machines, I think it is worth setting up some tests on at
> least one machine.
> 
> One way to make it testable, without affecting any of the
> existing debugger test cases, would be to add a new runtime option
> `--force-readline', which would cause MR_trace_readline() to use
> readline() even if the input file was a tty.

Done.
 
> > runtime/mercury_array_macros.h:
> > 	Define a macro MR_find_first_match, which is like MR_bsearch
> > 	except that it finds the first match, not an arbitary match.
> 
> s/arbitary/arbitrary/
> 
> > Index: runtime/mercury_array_macros.h
> >  /*
> > +** MR_find_first_match(int next, int& element, MR_bool& found, COMPARE)
> > +**
> > +** Given a sorted array, this macro finds the first element in the array
> > +** for which `COMPARE' is zero (MR_bsearch finds an arbitrary element).
> > +** Otherwise, the parameters and behaviour are the same as for MR_bsearch.
> 
> The parameter `next' is poorly named.
> I suggest s/next/num_elements/
> (both here and in MR_bsearch()).

Done.

> > +#define MR_find_first_match(next, element, found, COMPARE)		\
> > +	do {								\
> > +		MR_bsearch((next), (element), (found), (COMPARE));	\
> > +		if (found) {						\
> > +			while ((element) > 0) {				\
> > +				int	diff;				\
> 
> `diff' is unused here.
> That line should be deleted.

Done.
 
> > Index: trace/mercury_trace_alias.c
> ...
> > +static MR_bool
> > +MR_trace_filter_alias_completions(const char *word, MR_Completer_Data *data)
> 
> Why not `const MR_Completer_Data *data'?

Because the address of that function is passed to a function which expects
a function taking a non-const MR_Completer_Data.

> > Index: trace/mercury_trace_completion.c
> ...
> > +#define MR_MAX_COMMAND_LEN 32
> 
> You should document
> 	- what this is used for
> 	- what the units are
> 
> Also, 32 is probably too small.

I've moved this #define to where it is used so that the
meaning is obvious without documentation.

> > +typedef struct MR_String_Array_Completer_Data_struct {
> > +	int offset;
> > +	char **strings;
> > +} MR_String_Array_Completer_Data;
> 
> What does the `offset' field represent?
> Some comments here might help.

I've used more descriptive names, and move the typedef closer to
where it is used.
 
> > +char *MR_trace_line_completer(const char *passed_word, int state)
> > +{
> > +#ifndef MR_NO_USE_READLINE
> ... 150 lines of code ...
> > +#else
> > +    return NULL;
> > +#endif
> 
> You should add comments after the #else and #endif.
> 
> It would IMHO also be clearer to use `#ifdef' rather than `#ifndef' here,
> swapping the `then' and the `else' parts.  Then you won't need a comment
> on the #else.

Done.
 
> > +++ trace/mercury_trace_internal.c	4 Mar 2002 07:25:14 -0000
> > +		/*
> > +		** Some commands take set strings as arguments.
> > +		** This field is a NULL terminated array of those strings.
> > +		*/
> > +	const char *const	*MR_trace_command_arg_strings;
> 
> What is this field set to for commands which don't take strings as arguments?
> The comment should document that.

Done.
 
> > +static const char *const	MR_trace_print_cmd_args[] =
> > +		{"exception", "goal", NULL};
> 
> For use with filename completion, it might be worth making
> "print variables" have the same effect as "print".

"print goal" has the same effect as "print" (did you mean "print *"?).
I've added "*" to the list of completions.
 
> > +	** XXX Should we allow completion of options of comands?
> 
> s/comands/commands/
> 
> The answer to the XXX question is yes ;-)
> So I'd write that as
> 
> 	** XXX We should allow completion of options of commands.

I've added the options to the arrays of completions.

> > +	{ "queries", "query", NULL, MR_trace_null_completer },
> > +	{ "queries", "cc_query", NULL, MR_trace_null_completer },
> > +	{ "queries", "io_query", NULL, MR_trace_null_completer },
> 
> These should be using a module-name completer.
> An XXX comment is warranted.
>
> (Ideally the completer would be one that included all the modules
> in the program, not just those compiled with tracing enabled, so
> maybe this is not the same completer as for the `procedures' command.)

Done.
 
> > Index: trace/mercury_trace_tables.c
> > +/*
> > +** Convert all occurrences of `__' to `:'.
> 
> Since we're planning to eventually change the module qualifier
> from `:' to `.', it might be a good idea to use a macro
> MR_MODULE_SEPARATOR_CHAR instead of the various different
> hard-coded occurrences of `:'.

Separate change.
 
> > +*/
> > +static char *
> > +MR_translate_double_underscores(char *start)
> ...
> > +	return start;
> > +}
> 
> The return type for that should be `void *'.
> 
> (Whoever designed C's string handling routines has a lot to answer for ;-)

Sorry, you'll have to explain that.

Simon.

diff -u runtime/mercury_array_macros.h runtime/mercury_array_macros.h
--- runtime/mercury_array_macros.h
+++ runtime/mercury_array_macros.h
@@ -123,7 +123,7 @@
 	} while(0)
 
 /*
-** MR_bsearch(int next, int& element, MR_bool& found, COMPARE)
+** MR_bsearch(int num_elements, int& element, MR_bool& found, COMPARE)
 **
 ** Given a sorted array, this macro performs a binary search.
 ** If the search is successful, MR_bsearch sets the `found' parameter
@@ -131,7 +131,8 @@
 ** If the search is unsuccessful, MR_bsearch sets `found' to MR_FALSE;
 ** `element' will be clobbered.
 **
-** The number of the elements in the array is given by the `next' parameter.
+** The number of the elements in the array is given by the `num_elements'
+** parameter.
 ** The `COMPARE' parameter should be an expression of type int which compares
 ** the value at the index specified by the current value of `element'
 ** with the desired value, and returns <0, 0, or >0 according to whether 
@@ -142,7 +143,7 @@
 ** parameter.
 */
 
-#define MR_bsearch(next, element, found, COMPARE)			\
+#define MR_bsearch(num_elements, element, found, COMPARE)		\
 	do {								\
 		int	lo;						\
 		int	hi;						\
@@ -155,7 +156,7 @@
 		*/							\
 		(element) = 0;						\
 		lo = 0;							\
-		hi = (next) - 1;					\
+		hi = (num_elements) - 1;				\
 		(found) = MR_FALSE;					\
 		while (lo <= hi) {					\
 			(element) = (lo + hi) / 2;			\
@@ -172,19 +173,18 @@
 	} while(0)
 
 /*
-** MR_find_first_match(int next, int& element, MR_bool& found, COMPARE)
+** MR_find_first_match(int num_elements, int& element, MR_bool& found, COMPARE)
 **
 ** Given a sorted array, this macro finds the first element in the array
 ** for which `COMPARE' is zero (MR_bsearch finds an arbitrary element).
 ** Otherwise, the parameters and behaviour are the same as for MR_bsearch.
 */
 
-#define MR_find_first_match(next, element, found, COMPARE)		\
+#define MR_find_first_match(num_elements, element, found, COMPARE)	\
 	do {								\
-		MR_bsearch((next), (element), (found), (COMPARE));	\
+		MR_bsearch((num_elements), (element), (found), (COMPARE)); \
 		if (found) {						\
 			while ((element) > 0) {				\
-				int	diff;				\
 				(element)--;				\
 				if ((COMPARE) != 0) {			\
 					(element)++;			\
diff -u trace/mercury_trace_completion.c trace/mercury_trace_completion.c
--- trace/mercury_trace_completion.c
+++ trace/mercury_trace_completion.c
@@ -33,33 +33,6 @@
   #endif
 #endif
 
-#define MR_MAX_COMMAND_LEN 32
-
-typedef struct MR_String_Array_Completer_Data_struct {
-	int offset;
-	char **strings;
-} MR_String_Array_Completer_Data;
-
-typedef struct {
-	MR_Get_Slot_Name	MR_sorted_array_get_slot_name;
-	int			MR_sorted_array_offset;
-	int			MR_sorted_array_size;
-} MR_Sorted_Array_Completer_Data;
-
-typedef struct {
-	MR_Completer_Filter	MR_filter_func;
-	MR_Completer_Data	MR_filter_data;
-	MR_Free_Completer_Data	MR_filter_free_data;
-	MR_Completer_List *	MR_filter_list;
-} MR_Filter_Completer_Data;
-
-typedef struct {
-	MR_Completer_Map	MR_map_func;
-	MR_Completer_Data	MR_map_data;
-	MR_Free_Completer_Data	MR_map_free_data;
-	MR_Completer_List *	MR_map_list;
-} MR_Map_Completer_Data;
-
 	/*
 	** Complete on NULL terminated array of strings.
 	** The strings will not be `free'd.
@@ -71,28 +44,22 @@
 		size_t word_len, MR_Completer_List **list);
 static	void MR_trace_free_completer_list(MR_Completer_List *completer_list);
 
-static	char *MR_trace_sorted_array_completer_next(const char *word,
-		size_t word_length, MR_Completer_Data *data);
-
-static  char *MR_trace_filter_completer_next(const char *word,
-		size_t word_len, MR_Completer_Data *);
-static	void MR_trace_free_filter_completer_data(MR_Completer_Data data);
-
-static  char *MR_trace_map_completer_next(const char *word,
-		size_t word_len, MR_Completer_Data *);
-static	void MR_trace_free_map_completer_data(MR_Completer_Data data);
-
-static  char *MR_trace_string_array_completer_next(const char *word,
-		size_t word_len, MR_Completer_Data *data);
-
-static  char *MR_trace_filename_completer_next(const char *word,
-		size_t word_len, MR_Completer_Data *);
-
 static	char *MR_prepend_string(char *completion, MR_Completer_Data *data);
 
+/*---------------------------------------------------------------------------*/
+/*
+** Called by Readline when the user requests completion.
+** Examine Readline's input buffer to work out which completers
+** should be used, then apply them.
+** Readline passes zero for `state' on the first call, and non-zero
+** on subsequent calls.
+*/
+
 char *MR_trace_line_completer(const char *passed_word, int state)
 {
-#ifndef MR_NO_USE_READLINE
+#ifdef MR_NO_USE_READLINE
+    return NULL;
+#else
     static MR_Completer_List	*completer_list;
     static char			*word;
     static size_t		word_len;
@@ -187,8 +154,8 @@
 		/*
 		** We're completing an argument of the command.
 		*/
-
-		char command[MR_MAX_COMMAND_LEN];
+		#define MR_MAX_COMMAND_NAME_LEN 32
+		char command[MR_MAX_COMMAND_NAME_LEN];
 		char *expanded_command;
 		int command_len;
 		char **words;
@@ -198,7 +165,7 @@
 		MR_Completer_List *arg_completer;
 
 		command_len = command_end - command_start;
-		if (command_len >= MR_MAX_COMMAND_LEN) {
+		if (command_len >= MR_MAX_COMMAND_NAME_LEN) {
 			/* The string is too long to be a command. */
 			return NULL;
 		} else {
@@ -249,9 +216,7 @@
 	    word = NULL;
     }
     return completion;
-#else
-    return NULL;
-#endif
+#endif /* ! MR_NO_USE_READLINE */
 }
 
 static char *
@@ -270,6 +235,8 @@
 	return result;
 }
 
+/*---------------------------------------------------------------------------*/
+
 static char *
 MR_trace_completer_list_next(const char *word, size_t word_len,
 		MR_Completer_List **list)
@@ -312,12 +279,27 @@
 	}
 }
 
+/*---------------------------------------------------------------------------*/
+/* No completions. */
+
 MR_Completer_List *
 MR_trace_null_completer(const char *word, size_t word_len)
 {
 	return NULL;
 }
 
+/*---------------------------------------------------------------------------*/
+/* Complete on the labels of a sorted array. */
+
+typedef struct {
+	MR_Get_Slot_Name	MR_sorted_array_get_slot_name;
+	int			MR_sorted_array_current_offset;
+	int			MR_sorted_array_size;
+} MR_Sorted_Array_Completer_Data;
+
+static	char *MR_trace_sorted_array_completer_next(const char *word,
+		size_t word_length, MR_Completer_Data *data);
+
 MR_Completer_List *
 MR_trace_sorted_array_completer(const char *word, size_t word_length,
 		int array_size, MR_Get_Slot_Name get_slot_name)
@@ -343,7 +325,7 @@
 	if (found) {
 		data = MR_NEW(MR_Sorted_Array_Completer_Data);
 		data->MR_sorted_array_get_slot_name = get_slot_name;
-		data->MR_sorted_array_offset = slot;
+		data->MR_sorted_array_current_offset = slot;
 		data->MR_sorted_array_size = array_size;
 		(completer) = MR_new_completer_elem(
 			MR_trace_sorted_array_completer_next,
@@ -363,11 +345,13 @@
 
 	data = (MR_Sorted_Array_Completer_Data *) *completer_data;
 	
-	if (data->MR_sorted_array_offset < data->MR_sorted_array_size) {
+	if (data->MR_sorted_array_current_offset
+			< data->MR_sorted_array_size)
+	{
 		completion = data->MR_sorted_array_get_slot_name(
-				data->MR_sorted_array_offset);
+				data->MR_sorted_array_current_offset);
 		if (MR_strneq(completion, word, word_length)) {
-			data->MR_sorted_array_offset++;
+			data->MR_sorted_array_current_offset++;
 			return MR_copy_string(completion);
 		} else {
 			return NULL;
@@ -377,13 +361,24 @@
 	}
 }
 
+/*---------------------------------------------------------------------------*/
+/* Complete on the elements of an unsorted array of strings. */
+
+typedef struct MR_String_Array_Completer_Data_struct {
+	char			**MR_string_array;
+	int			MR_string_array_current_offset;
+} MR_String_Array_Completer_Data;
+
+static  char *MR_trace_string_array_completer_next(const char *word,
+		size_t word_len, MR_Completer_Data *data);
+
 static MR_Completer_List *
 MR_trace_string_array_completer(const char *const *strings)
 {
 	MR_String_Array_Completer_Data *data;
 	data = MR_NEW(MR_String_Array_Completer_Data);
-	data->offset = 0;
-	data->strings = (char **) strings;
+	data->MR_string_array = (char **) strings;
+	data->MR_string_array_current_offset = 0;
 	return MR_new_completer_elem(&MR_trace_string_array_completer_next,
 		(MR_Completer_Data) data, MR_free_func);
 }
@@ -398,8 +393,9 @@
 	completer_data = (MR_String_Array_Completer_Data *) *data;
 
 	while (1) {
-		result = completer_data->strings[completer_data->offset];
-		completer_data->offset++;
+		result = completer_data->MR_string_array[
+			completer_data->MR_string_array_current_offset];
+		completer_data->MR_string_array_current_offset++;
 		if (result == NULL) {
 			return NULL;
 		} else {
@@ -410,6 +406,12 @@
 	}
 }
 
+/*---------------------------------------------------------------------------*/
+/* Use Readline's filename completer. */
+
+static  char *MR_trace_filename_completer_next(const char *word,
+		size_t word_len, MR_Completer_Data *);
+
 MR_Completer_List *
 MR_trace_filename_completer(const char *word, size_t word_len)
 {
@@ -417,7 +419,6 @@
 		(MR_Completer_Data) 0, MR_trace_no_free);
 }
 
-
 static char *
 MR_trace_filename_completer_next(const char *word, size_t word_len,
 		MR_Completer_Data *data)
@@ -428,6 +429,20 @@
 	return filename_completion_function((char *) word, state);
 }
 
+/*---------------------------------------------------------------------------*/
+/* Apply a filter to the output of a completer. */
+
+typedef struct {
+	MR_Completer_Filter	MR_filter_func;
+	MR_Completer_Data	MR_filter_data;
+	MR_Free_Completer_Data	MR_filter_free_data;
+	MR_Completer_List *	MR_filter_list;
+} MR_Filter_Completer_Data;
+
+static  char *MR_trace_filter_completer_next(const char *word,
+		size_t word_len, MR_Completer_Data *);
+static	void MR_trace_free_filter_completer_data(MR_Completer_Data data);
+
 MR_Completer_List *
 MR_trace_filter_completer(MR_Completer_Filter filter,
 			MR_Completer_Data filter_data,
@@ -479,6 +494,20 @@
 	MR_free(data);
 }
 
+/*---------------------------------------------------------------------------*/
+/* Apply a mapping function to the output of a completer. */
+
+typedef struct {
+	MR_Completer_Map	MR_map_func;
+	MR_Completer_Data	MR_map_data;
+	MR_Free_Completer_Data	MR_map_free_data;
+	MR_Completer_List *	MR_map_list;
+} MR_Map_Completer_Data;
+
+static  char *MR_trace_map_completer_next(const char *word,
+		size_t word_len, MR_Completer_Data *);
+static	void MR_trace_free_map_completer_data(MR_Completer_Data data);
+
 MR_Completer_List *
 MR_trace_map_completer(MR_Completer_Map map, MR_Completer_Data map_data,
 			MR_Free_Completer_Data free_data,
@@ -522,6 +551,8 @@
 	MR_trace_free_completer_list(data->MR_map_list);
 	MR_free(data);
 }
+
+/*---------------------------------------------------------------------------*/
 
 MR_Completer_List *
 MR_new_completer_elem(MR_Completer completer, MR_Completer_Data data,
diff -u trace/mercury_trace_completion.h trace/mercury_trace_completion.h
--- trace/mercury_trace_completion.h
+++ trace/mercury_trace_completion.h
@@ -13,6 +13,9 @@
 #ifndef MR_TRACE_COMPLETION_H
 #define MR_TRACE_COMPLETION_H
 
+#include "mercury_std.h"	/* for MR_bool */
+#include <stdlib.h>		/* for size_t */
+
 /*
 ** Called by Readline when the user requests completion.
 ** Examine Readline's input buffer to work out which completers
diff -u trace/mercury_trace_internal.c trace/mercury_trace_internal.c
--- trace/mercury_trace_internal.c
+++ trace/mercury_trace_internal.c
@@ -227,8 +227,9 @@
 	const char		*MR_trace_command_name;
 
 		/*
-		** Some commands take set strings as arguments.
-		** This field is a NULL terminated array of those strings.
+		** Some commands take fixed strings as arguments.
+		** This field is a NULL terminated array of those strings,
+		** or NULL if there are no fixed strings.
 		*/
 	const char *const	*MR_trace_command_arg_strings;
 
@@ -4131,15 +4132,42 @@
 		parent_filename, parent_lineno, indent);
 }
 
+static const char *const	MR_trace_movement_cmd_args[] =
+		{"-N", "-S", "-a", "-n", "-s",
+		"--none", "--some", "--all", "--strict", "--no-strict", NULL};
+
 static const char *const	MR_trace_print_cmd_args[] =
-		{"exception", "goal", NULL};
+		{"-f", "-p", "-v", "--flat", "--pretty", "--verbose",
+		"exception", "goal", "*", NULL};
+
+		/*
+		** It's better to have a single completion where possible,
+		** so don't include `-d' here.
+		*/
+static const char *const	MR_trace_stack_cmd_args[] =
+		{"--detailed", NULL};
 
 static const char *const	MR_trace_set_cmd_args[] =
-		{"format", "depth", "size", "width", "lines",
+		{"-A", "-B", "-P", "-f", "-p", "-v",
+		"--print-all", "--print", "--browse",
+		"--flat", "--pretty", "--verbose",
+		"format", "depth", "size", "width", "lines",
 		"flat", "pretty", "verbose", NULL};
 
+static const char *const	MR_trace_view_cmd_args[] =
+		{"-c", "-f", "-n", "-s", "-t", "-v", "-w", "-2",
+		"--close", "--verbose", "--force", "--split-screen",
+		"--window-command", "--server-command", "--server-name",
+		"--timeout", NULL};
+
 static const char *const	MR_trace_break_cmd_args[] =
-		{"here", "info", NULL};
+		{"-A", "-E", "-I", "-O", "-P", "-S", "-a", "-e", "-i",
+		"--all", "--entry", "--ignore-entry", "--ignore-interface",
+		"--interface", "--print", "--select-all", "--select-one",
+		"--stop", "here", "info", NULL};
+
+static const char *const	MR_trace_ignore_cmd_args[] =
+		{"-E", "-I", "--ignore-entry", "--ignore-interface", NULL};
 
 static const char *const	MR_trace_printlevel_cmd_args[] =
 		{"none", "some", "all", NULL};
@@ -4156,43 +4184,72 @@
 static const char *const	MR_trace_table_io_cmd_args[] =
 		{"stats", "start", "end", NULL};
 
+		/*
+		** It's better to have a single completion where possible,
+		** so don't include `-i' here.
+		*/
+static const char *const	MR_trace_source_cmd_args[] =
+		{"--ignore-errors", NULL};
+
+static const char *const	MR_trace_quit_cmd_args[] =
+		{"-y", NULL};
+
 static const MR_Trace_Command_Info	MR_trace_valid_command_list[] =
 {
 	/*
 	** The first two fields of this block should be the same
 	** as in the file doc/mdb_command_list.
-	** XXX Should we allow completion of options of comands?
 	*/
 
-	{ "queries", "query", NULL, MR_trace_null_completer },
-	{ "queries", "cc_query", NULL, MR_trace_null_completer },
-	{ "queries", "io_query", NULL, MR_trace_null_completer },
-	{ "forward", "step", NULL, MR_trace_null_completer },
-	{ "forward", "goto", NULL, MR_trace_null_completer },
-	{ "forward", "next", NULL, MR_trace_null_completer },
-	{ "forward", "finish", NULL, MR_trace_null_completer },
-	{ "forward", "exception", NULL, MR_trace_null_completer },
-	{ "forward", "return", NULL, MR_trace_null_completer },
-	{ "forward", "forward", NULL, MR_trace_null_completer },
-	{ "forward", "mindepth", NULL, MR_trace_null_completer },
-	{ "forward", "maxdepth", NULL, MR_trace_null_completer },
-	{ "forward", "continue", NULL, MR_trace_null_completer },
+	/*
+	** XXX For queries we should complete on all modules, not
+	** just those that were compiled with tracing enabled.
+	*/
+	{ "queries", "query", NULL, MR_trace_module_completer },
+	{ "queries", "cc_query", NULL, MR_trace_module_completer },
+	{ "queries", "io_query", NULL, MR_trace_module_completer },
+	{ "forward", "step", MR_trace_movement_cmd_args,
+					MR_trace_null_completer },
+	{ "forward", "goto", MR_trace_movement_cmd_args,
+					MR_trace_null_completer },
+	{ "forward", "next", MR_trace_movement_cmd_args,
+					MR_trace_null_completer },
+	{ "forward", "finish", MR_trace_movement_cmd_args,
+					MR_trace_null_completer },
+	{ "forward", "exception", MR_trace_movement_cmd_args,
+					MR_trace_null_completer },
+	{ "forward", "return", MR_trace_movement_cmd_args,
+					MR_trace_null_completer },
+	{ "forward", "forward", MR_trace_movement_cmd_args,
+					MR_trace_null_completer },
+	{ "forward", "mindepth", MR_trace_movement_cmd_args,
+					MR_trace_null_completer },
+	{ "forward", "maxdepth", MR_trace_movement_cmd_args,
+					MR_trace_null_completer },
+	{ "forward", "continue", MR_trace_movement_cmd_args,
+					MR_trace_null_completer },
 	{ "backward", "retry", NULL, MR_trace_null_completer },
 	{ "browsing", "vars", NULL, MR_trace_null_completer },
 	{ "browsing", "print", MR_trace_print_cmd_args,
 					MR_trace_var_completer },
 	{ "browsing", "browse", MR_trace_print_cmd_args,
 					MR_trace_var_completer },
-	{ "browsing", "stack", NULL, MR_trace_null_completer },
-	{ "browsing", "up", NULL, MR_trace_null_completer },
-	{ "browsing", "down", NULL, MR_trace_null_completer },
-	{ "browsing", "level", NULL, MR_trace_null_completer },
+	{ "browsing", "stack", MR_trace_stack_cmd_args,
+					MR_trace_null_completer },
+	{ "browsing", "up", MR_trace_stack_cmd_args,
+					MR_trace_null_completer },
+	{ "browsing", "down", MR_trace_stack_cmd_args,
+					MR_trace_null_completer },
+	{ "browsing", "level", MR_trace_stack_cmd_args,
+					MR_trace_null_completer },
 	{ "browsing", "current", NULL, MR_trace_null_completer },
 	{ "browsing", "set", MR_trace_set_cmd_args, MR_trace_null_completer },
-	{ "browsing", "view", NULL, MR_trace_null_completer },
+	{ "browsing", "view", MR_trace_view_cmd_args,
+					MR_trace_null_completer },
 	{ "breakpoint", "break", MR_trace_break_cmd_args,
 					MR_trace_breakpoint_completer },
-	{ "breakpoint", "ignore", NULL, MR_trace_null_completer },
+	{ "breakpoint", "ignore", MR_trace_ignore_cmd_args,
+					MR_trace_null_completer },
 	{ "breakpoint", "enable", NULL, MR_trace_null_completer },
 	{ "breakpoint", "disable", NULL, MR_trace_null_completer },
 	{ "breakpoint", "delete", NULL, MR_trace_null_completer },
@@ -4215,11 +4272,12 @@
 	{ "help", "document", NULL, MR_trace_null_completer },
 	{ "help", "help", NULL, MR_trace_help_completer },
 #ifdef	MR_TRACE_HISTOGRAM
-	{ "exp", "histogram_all", NULL, MR_trace_null_completer },
-	{ "exp", "histogram_exp", NULL, MR_trace_null_completer },
+	{ "exp", "histogram_all", NULL, MR_trace_filename_completer },
+	{ "exp", "histogram_exp", NULL, MR_trace_filename_completer },
 	{ "exp", "clear_histogram", NULL, MR_trace_null_completer },
 #endif
-	{ "developer", "nondet_stack", NULL, MR_trace_null_completer },
+	{ "developer", "nondet_stack", MR_trace_stack_cmd_args,
+					MR_trace_null_completer },
 #ifdef	MR_USE_MINIMAL_MODEL
 	{ "developer", "gen_stack", NULL, MR_trace_null_completer },
 #endif
@@ -4227,13 +4285,14 @@
 	{ "developer", "all_regs", NULL, MR_trace_null_completer },
 	{ "developer", "table_io", MR_trace_table_io_cmd_args,
 					MR_trace_null_completer },
-	{ "developer", "proc_stats", NULL, MR_trace_null_completer },
-	{ "developer", "label_stats", NULL, MR_trace_null_completer },
+	{ "developer", "proc_stats", NULL, MR_trace_filename_completer },
+	{ "developer", "label_stats", NULL, MR_trace_filename_completer },
 	{ "developer", "print_optionals", MR_trace_on_off_args,
 					MR_trace_null_completer },
-	{ "misc", "source", NULL, MR_trace_filename_completer },
+	{ "misc", "source", MR_trace_source_cmd_args,
+					MR_trace_filename_completer },
 	{ "misc", "save", NULL, MR_trace_filename_completer },
-	{ "misc", "quit", NULL, NULL},
+	{ "misc", "quit", MR_trace_quit_cmd_args, NULL},
 	/* End of doc/mdb_command_list. */
 	{ NULL, "NUMBER", NULL, MR_trace_null_completer },
 	{ NULL, "EMPTY", NULL, MR_trace_null_completer },
diff -u trace/mercury_trace_readline.c trace/mercury_trace_readline.c
--- trace/mercury_trace_readline.c
+++ trace/mercury_trace_readline.c
@@ -17,6 +17,7 @@
 #include "mercury_array_macros.h"
 #include "mercury_memory.h"
 #include "mercury_std.h"
+#include "mercury_wrapper.h"
 
 #include "mercury_trace_readline.h"
 #include "mercury_trace_completion.h"
@@ -29,6 +30,8 @@
     extern FILE *rl_outstream;
     extern char (*rl_completion_entry_function)(const char *, int);
     extern const char *rl_readline_name;
+    extern void (*rl_prep_term_function)(int);
+    extern void (*rl_deprep_term_function)(void);
   #endif
   #ifdef MR_HAVE_READLINE_HISTORY_H
     #include "readline/history.h"
@@ -44,6 +47,9 @@
 /* The initial size of the array of characters used to hold the line. */
 #define	MR_INIT_BUF_LEN		80
 
+static	void	MR_dummy_prep_term_function(int ignored);
+static	void	MR_dummy_deprep_term_function(void);
+
 /*
 ** Print the prompt to the `out' file, read a line from the `in' file,
 ** and return it in a MR_malloc'd buffer holding the line (without the
@@ -57,9 +63,11 @@
 #if (defined(isatty) || defined(MR_HAVE_ISATTY)) \
  && (defined(fileno) || defined(MR_HAVE_FILENO)) \
  && !defined(MR_NO_USE_READLINE)
-	/* use readline, if the input file is a terminal */
-	if (isatty(fileno(in))) {
-		char	*line;
+	char	*line;
+ 	MR_bool	in_isatty;
+
+	in_isatty = isatty(fileno(in));
+	if (in_isatty || MR_force_readline) {
 
 		rl_instream = in;
 		rl_outstream = out;
@@ -71,9 +79,23 @@
 		** function pointers).
 		*/
 		rl_completion_entry_function =
-				(void *) &MR_trace_line_completer;
+			(void *) &MR_trace_line_completer;
 		rl_readline_name = "mdb";
 
+		if (!in_isatty) {
+			/*
+			** This is necessary for tests/debugger/completion,
+			** otherwise we get lots of messages about readline
+			** not being able to get the terminal settings.
+			** This is possibly a bit flaky, but it's only
+			** used by our tests.
+			*/
+			rl_prep_term_function =
+				(void *) MR_dummy_prep_term_function;
+			rl_deprep_term_function =
+				(void *) MR_dummy_deprep_term_function;
+		}	
+
 		line = readline((char *) prompt);
 
 		/*
@@ -136,4 +158,14 @@
 		MR_free(contents);
 		return NULL;
 	}
+}
+
+static void
+MR_dummy_prep_term_function(int ignored)
+{
+}
+
+static void
+MR_dummy_deprep_term_function(void)
+{
 }
diff -u trace/mercury_trace_tables.c trace/mercury_trace_tables.c
--- trace/mercury_trace_tables.c
+++ trace/mercury_trace_tables.c
@@ -370,7 +370,7 @@
 
 	str = start;
 	while (*str) {
-		if (*str == '_' && *(str+ 1) == '_') {
+		if (*str == '_' && *(str + 1) == '_') {
 			*(str - double_underscores) = ':';
 			double_underscores++;
 			str++;
only in patch2:
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/debugger/completion.sub2.sub3.m	5 Mar 2002 15:13:02 -0000
@@ -0,0 +1,9 @@
+:- module completion__sub2__sub3.
+
+:- interface.
+
+:- func zabc3 = int.
+
+:- implementation.
+
+zabc3 = 3.
only in patch2:
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/debugger/completion.sub2.m	5 Mar 2002 15:15:59 -0000
@@ -0,0 +1,11 @@
+:- module completion__sub2.
+
+:- interface.
+
+:- include_module completion__sub2__sub3.
+
+:- func z2 = int.
+
+:- implementation.
+
+z2 = 2.
only in patch2:
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/debugger/completion.sub1.m	5 Mar 2002 15:10:56 -0000
@@ -0,0 +1,13 @@
+:- module completion__sub1.
+
+:- interface.
+
+:- func z1 = int.
+
+:- pred zp(int::out) is det.
+
+:- implementation.
+
+z1 = 1.
+
+zp(1).
only in patch2:
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/debugger/completion.m	5 Mar 2002 15:13:43 -0000
@@ -0,0 +1,20 @@
+:- module completion.
+
+:- interface.
+
+:- import_module io.
+
+:- include_module completion__sub1, completion__sub2.
+
+:- pred main(io__state::di, io__state::uo) is det.
+
+:- implementation.
+
+main -->
+	io__write_string("ok\n").
+
+:- func z = int.
+z = 0.
+
+:- func zz = int.
+zz = 0.
only in patch2:
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/debugger/completion.inputrc	5 Mar 2002 08:23:54 -0000
@@ -0,0 +1,9 @@
+# Don't query the user if there are too many completions.
+set completion-query-items 100000
+
+# Display all completions immediately, without
+# requiring multiple `complete' commands.
+set show-all-if-ambiguous on
+
+# Make the completion requests show up in the input file.
+@: complete
only in patch2:
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/debugger/completion.inp	6 Mar 2002 10:41:14 -0000
@@ -0,0 +1,13 @@
+echo on
+ at h@e at v@a@
+p --f@@H@
+sta@ @
+proc at e@compl@:@1
+set --f at fo@p@
+un at ex@
+b z at a@
+b pred*@z@
+b compl at s@1 at 1
+b compl at s@2 at s@
+2d at e@
+c
only in patch2:
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/debugger/completion.exp	6 Mar 2002 10:42:00 -0000
@@ -0,0 +1,96 @@
+Melbourne Mercury Debugger, mdb version DEV.
+Copyright 1998 The University of Melbourne, Australia.
+mdb is free software, covered by the GNU General Public License.
+There is absolutely no warranty for mdb.
+       1:      1  1 CALL pred completion:main/2-0 (det) completion.m:13
+mdb> echo on
+Command echo enabled.
+mdb> 
+?                  down               maxdepth           return
+P                  e                  mindepth           s
+alias              echo               mmc_options        save
+all_regs           enable             modules            scope
+b                  exception          next               scroll
+break              excp               nondet_stack       set
+browse             f                  p                  source
+c                  finish             print              stack
+cc_query           forward            print_optionals    stack_regs
+context            g                  printlevel         step
+continue           goto               proc_stats         table_io
+current            h                  procedures         unalias
+d                  help               query              up
+delete             ignore             quit               v
+disable            io_query           r                  vars
+document           label_stats        register           view
+document_category  level              retry              
+
+h     help  
+
+vars  view  
+help vars 
+vars
+     Prints the names of all the known variables in the current
+     environment, together with an ordinal number for each variable.
+
+
+mdb> 
+*           --pretty    -f          -v          exception   
+--flat      --verbose   -p          HeadVar__1  goal        
+p --flat HeadVar__1 
+       HeadVar__1             	state('<<c_pointer>>')
+mdb> 
+stack       stack_regs  
+stack --detailed 
+   0       1       1    1 pred completion:main/2-0 (det) (completion.m:13) (empty)
+mdb> 
+proc_stats  procedures  
+
+completion            completion:sub2       
+completion:sub1       completion:sub2:sub3  
+
+completion:sub1       completion:sub2       completion:sub2:sub3
+procedures completion:sub1
+Registering debuggable procedures... done.
+There are 4 debuggable modules, with a total of 7 procedures.
+List of procedures in module `completion:sub1'
+
+pred completion:sub1:zp/1-0 (det)
+func completion:sub1:z1/0-0 (det)
+mdb> set --flat format pretty 
+mdb> unalias excp 
+Alias `excp' removed.
+mdb> 
+z      z1     z2     zabc3  zp     zz     
+b zabc3 
+ 0: + stop  interface func completion:sub2:sub3:zabc3/0-0 (det)
+mdb> 
+pred*completion:            pred*completion:sub2:sub3:
+pred*completion:sub1:       pred*main
+pred*completion:sub2:       pred*zp
+b pred*zp 
+ 1: + stop  interface pred completion:sub1:zp/1-0 (det)
+mdb> 
+completion:            completion:sub2:       
+completion:sub1:       completion:sub2:sub3:  
+
+completion:sub1:       completion:sub2:       completion:sub2:sub3:
+
+completion:sub1:z1  completion:sub1:zp  
+b completion:sub1:z1
+ 2: + stop  interface func completion:sub1:z1/0-0 (det)
+mdb> 
+completion:            completion:sub2:       
+completion:sub1:       completion:sub2:sub3:  
+
+completion:sub1:       completion:sub2:       completion:sub2:sub3:
+
+completion:sub2:       completion:sub2:sub3:  
+b completion:sub2:sub3:zabc3 
+ 3: + stop  interface func completion:sub2:sub3:zabc3/0-0 (det)
+mdb> 
+2d                  2disable            2document_category
+2delete             2document           2down
+2delete 
+ 2: E stop  interface func completion:sub1:z1/0-0 (det)
+mdb> c
+ok
only in patch2:
--- tests/debugger/Mmakefile	2 Mar 2002 10:22:05 -0000	1.66
+++ tests/debugger/Mmakefile	5 Mar 2002 14:57:11 -0000
@@ -28,6 +28,7 @@
 	breakpoints			\
 	browse_pretty			\
 	cmd_quote			\
+	completion			\
 	debugger_regs			\
 	exception_cmd			\
 	exception_value			\
@@ -46,6 +47,10 @@
 	resume_typeinfos		\
 	shallow
 
+# The completion test requires mdb to use readline, even though
+# the input is not a terminal.
+MLFLAGS-completion = --runtime-flags --force-readline
+
 MCFLAGS-shallow = --trace shallow
 MCFLAGS-tabled_read = --trace-table-io
 MCFLAGS-tabled_read_decl = --trace-table-io-decl
@@ -128,6 +133,11 @@
 cmd_quote.out: cmd_quote cmd_quote.inp
 	$(MDB) ./cmd_quote < cmd_quote.inp 2>&1 | \
 		sed 's/io.m:[0-9]*/io.m:NNNN/g' > cmd_quote.out 2>&1
+
+# Set up readline to make it easier to use completion non-interactively.
+completion.out: completion completion.inp
+	INPUTRC=completion.inputrc $(MDB) ./completion \
+		< completion.inp > completion.out 2>&1
 
 debugger_regs.out: debugger_regs debugger_regs.inp
 	$(MDB) ./debugger_regs < debugger_regs.inp > debugger_regs.out 2>&1
only in patch2:
--- runtime/mercury_wrapper.h	24 Feb 2002 11:53:37 -0000	1.51
+++ runtime/mercury_wrapper.h	4 Mar 2002 13:40:39 -0000
@@ -220,6 +220,9 @@
 /* should mdb be started in a window */
 extern	MR_bool		MR_mdb_in_window;
 
+/* use readline() in the debugger even if the input stream is not a tty */
+extern	MR_bool		MR_force_readline;
+
 /* size of the primary cache */
 extern	size_t		MR_pcache_size;
 
only in patch2:
--- runtime/mercury_wrapper.c	24 Feb 2002 11:53:36 -0000	1.102
+++ runtime/mercury_wrapper.c	5 Mar 2002 14:53:44 -0000
@@ -103,6 +103,9 @@
 const char	*MR_mdb_err_filename = NULL;
 MR_bool		MR_mdb_in_window = MR_FALSE;
 
+/* use readline() in the debugger even if the input stream is not a tty */
+MR_bool		MR_force_readline = MR_FALSE;
+
 /* other options */
 
 MR_bool		MR_check_space = MR_FALSE;
@@ -753,6 +756,7 @@
 	MR_MDB_OUT,
 	MR_MDB_ERR,
 	MR_MDB_IN_WINDOW,
+	MR_FORCE_READLINE,
 	MR_NUM_OUTPUT_ARGS
 };
 
@@ -773,6 +777,7 @@
 	{ "mdb-out", 			1, 0, MR_MDB_OUT },
 	{ "mdb-err", 			1, 0, MR_MDB_ERR },
 	{ "mdb-in-window",		0, 0, MR_MDB_IN_WINDOW },
+	{ "force-readline",		0, 0, MR_FORCE_READLINE },
 	{ "num-output-args", 		1, 0, MR_NUM_OUTPUT_ARGS }
 };
 
@@ -901,6 +906,18 @@
 			MR_mdb_in_window = MR_TRUE;
 			break;
 
+		case MR_FORCE_READLINE:
+			MR_force_readline = MR_TRUE;
+#ifdef MR_NO_USE_READLINE
+			printf(
+"Mercury runtime: `--force-readline' is specified in MERCURY_OPTIONS\n");
+			printf(
+"but readline() is not available.\n");	
+			fflush(stdout);
+			exit(1);
+#endif
+			break;
+
 		case 'a':
 			benchmark_all_solns = MR_TRUE;
 			break;
@@ -1092,7 +1109,7 @@
 			"the word `%s'\n"
 			"which is not an option. Please refer to the "
 			"Environment Variables section\n"
-			"of the Mercury user's guide for details.\n",
+			"of the Mercury User's Guide for details.\n",
 			argv[MR_optind]);
 		fflush(stdout);
 		exit(1);
@@ -1105,7 +1122,7 @@
 	printf("The MERCURY_OPTIONS environment variable "
 		"contains an invalid option.\n"
 		"Please refer to the Environment Variables section of "
-		"the Mercury\nuser's guide for details.\n");
+		"the Mercury\nUser's Guide for details.\n");
 	fflush(stdout);
 	exit(1);
 } /* end usage() */
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list