Browse Source

Completion refactoring. Fix Issue #29

git-svn-id: https://klish.googlecode.com/svn/trunk@395 0eaa4687-2ee9-07dd-09d9-bcdd2d2dd5fb
Serj Kalichev 13 years ago
parent
commit
8aa26ccdac

+ 1 - 31
Makefile.in

@@ -215,8 +215,6 @@ am_libclish_la_OBJECTS = clish/libclish_la-clish_access_callback.lo \
 	clish/shell/libclish_la-shell_find_create_ptype.lo \
 	clish/shell/libclish_la-shell_find_create_view.lo \
 	clish/shell/libclish_la-shell_find_view.lo \
-	clish/shell/libclish_la-shell_getfirst_command.lo \
-	clish/shell/libclish_la-shell_getnext_command.lo \
 	clish/shell/libclish_la-shell_help.lo \
 	clish/shell/libclish_la-shell_insert_ptype.lo \
 	clish/shell/libclish_la-shell_insert_view.lo \
@@ -749,9 +747,7 @@ libclish_la_SOURCES = clish/clish_access_callback.c \
 	clish/shell/shell_execute.c \
 	clish/shell/shell_find_create_ptype.c \
 	clish/shell/shell_find_create_view.c \
-	clish/shell/shell_find_view.c \
-	clish/shell/shell_getfirst_command.c \
-	clish/shell/shell_getnext_command.c clish/shell/shell_help.c \
+	clish/shell/shell_find_view.c clish/shell/shell_help.c \
 	clish/shell/shell_insert_ptype.c \
 	clish/shell/shell_insert_view.c clish/shell/shell_new.c \
 	clish/shell/shell_parse.c clish/shell/shell_pop_file.c \
@@ -1072,12 +1068,6 @@ clish/shell/libclish_la-shell_find_create_view.lo:  \
 clish/shell/libclish_la-shell_find_view.lo:  \
 	clish/shell/$(am__dirstamp) \
 	clish/shell/$(DEPDIR)/$(am__dirstamp)
-clish/shell/libclish_la-shell_getfirst_command.lo:  \
-	clish/shell/$(am__dirstamp) \
-	clish/shell/$(DEPDIR)/$(am__dirstamp)
-clish/shell/libclish_la-shell_getnext_command.lo:  \
-	clish/shell/$(am__dirstamp) \
-	clish/shell/$(DEPDIR)/$(am__dirstamp)
 clish/shell/libclish_la-shell_help.lo: clish/shell/$(am__dirstamp) \
 	clish/shell/$(DEPDIR)/$(am__dirstamp)
 clish/shell/libclish_la-shell_insert_ptype.lo:  \
@@ -1707,10 +1697,6 @@ mostlyclean-compile:
 	-rm -f clish/shell/libclish_la-shell_find_create_view.lo
 	-rm -f clish/shell/libclish_la-shell_find_view.$(OBJEXT)
 	-rm -f clish/shell/libclish_la-shell_find_view.lo
-	-rm -f clish/shell/libclish_la-shell_getfirst_command.$(OBJEXT)
-	-rm -f clish/shell/libclish_la-shell_getfirst_command.lo
-	-rm -f clish/shell/libclish_la-shell_getnext_command.$(OBJEXT)
-	-rm -f clish/shell/libclish_la-shell_getnext_command.lo
 	-rm -f clish/shell/libclish_la-shell_help.$(OBJEXT)
 	-rm -f clish/shell/libclish_la-shell_help.lo
 	-rm -f clish/shell/libclish_la-shell_insert_ptype.$(OBJEXT)
@@ -2036,8 +2022,6 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@clish/shell/$(DEPDIR)/libclish_la-shell_find_create_ptype.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@clish/shell/$(DEPDIR)/libclish_la-shell_find_create_view.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@clish/shell/$(DEPDIR)/libclish_la-shell_find_view.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@clish/shell/$(DEPDIR)/libclish_la-shell_getfirst_command.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@clish/shell/$(DEPDIR)/libclish_la-shell_getnext_command.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@clish/shell/$(DEPDIR)/libclish_la-shell_help.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@clish/shell/$(DEPDIR)/libclish_la-shell_insert_ptype.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@clish/shell/$(DEPDIR)/libclish_la-shell_insert_view.Plo@am__quote@
@@ -2366,20 +2350,6 @@ clish/shell/libclish_la-shell_find_view.lo: clish/shell/shell_find_view.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclish_la_CFLAGS) $(CFLAGS) -c -o clish/shell/libclish_la-shell_find_view.lo `test -f 'clish/shell/shell_find_view.c' || echo '$(srcdir)/'`clish/shell/shell_find_view.c
 
-clish/shell/libclish_la-shell_getfirst_command.lo: clish/shell/shell_getfirst_command.c
-@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclish_la_CFLAGS) $(CFLAGS) -MT clish/shell/libclish_la-shell_getfirst_command.lo -MD -MP -MF clish/shell/$(DEPDIR)/libclish_la-shell_getfirst_command.Tpo -c -o clish/shell/libclish_la-shell_getfirst_command.lo `test -f 'clish/shell/shell_getfirst_command.c' || echo '$(srcdir)/'`clish/shell/shell_getfirst_command.c
-@am__fastdepCC_TRUE@	$(am__mv) clish/shell/$(DEPDIR)/libclish_la-shell_getfirst_command.Tpo clish/shell/$(DEPDIR)/libclish_la-shell_getfirst_command.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='clish/shell/shell_getfirst_command.c' object='clish/shell/libclish_la-shell_getfirst_command.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclish_la_CFLAGS) $(CFLAGS) -c -o clish/shell/libclish_la-shell_getfirst_command.lo `test -f 'clish/shell/shell_getfirst_command.c' || echo '$(srcdir)/'`clish/shell/shell_getfirst_command.c
-
-clish/shell/libclish_la-shell_getnext_command.lo: clish/shell/shell_getnext_command.c
-@am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclish_la_CFLAGS) $(CFLAGS) -MT clish/shell/libclish_la-shell_getnext_command.lo -MD -MP -MF clish/shell/$(DEPDIR)/libclish_la-shell_getnext_command.Tpo -c -o clish/shell/libclish_la-shell_getnext_command.lo `test -f 'clish/shell/shell_getnext_command.c' || echo '$(srcdir)/'`clish/shell/shell_getnext_command.c
-@am__fastdepCC_TRUE@	$(am__mv) clish/shell/$(DEPDIR)/libclish_la-shell_getnext_command.Tpo clish/shell/$(DEPDIR)/libclish_la-shell_getnext_command.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='clish/shell/shell_getnext_command.c' object='clish/shell/libclish_la-shell_getnext_command.lo' libtool=yes @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@	DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclish_la_CFLAGS) $(CFLAGS) -c -o clish/shell/libclish_la-shell_getnext_command.lo `test -f 'clish/shell/shell_getnext_command.c' || echo '$(srcdir)/'`clish/shell/shell_getnext_command.c
-
 clish/shell/libclish_la-shell_help.lo: clish/shell/shell_help.c
 @am__fastdepCC_TRUE@	$(LIBTOOL)  --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclish_la_CFLAGS) $(CFLAGS) -MT clish/shell/libclish_la-shell_help.lo -MD -MP -MF clish/shell/$(DEPDIR)/libclish_la-shell_help.Tpo -c -o clish/shell/libclish_la-shell_help.lo `test -f 'clish/shell/shell_help.c' || echo '$(srcdir)/'`clish/shell/shell_help.c
 @am__fastdepCC_TRUE@	$(am__mv) clish/shell/$(DEPDIR)/libclish_la-shell_help.Tpo clish/shell/$(DEPDIR)/libclish_la-shell_help.Plo

+ 15 - 16
clish/ptype.h

@@ -19,6 +19,7 @@ typedef struct clish_ptype_s clish_ptype_t;
 
 #include "lub/types.h"
 #include "lub/bintree.h"
+#include "lub/argv.h"
 
 #include <stddef.h>
 
@@ -80,19 +81,19 @@ size_t clish_ptype_bt_offset(void);
 const char *clish_ptype_method__get_name(clish_ptype_method_e method);
 clish_ptype_method_e clish_ptype_method_resolve(const char *method_name);
 const char *clish_ptype_preprocess__get_name(clish_ptype_preprocess_e
-					     preprocess);
+	preprocess);
 clish_ptype_preprocess_e clish_ptype_preprocess_resolve(const char
-							*preprocess_name);
+	*preprocess_name);
 clish_ptype_t *clish_ptype_new(const char *name, const char *text,
-			       const char *pattern, clish_ptype_method_e method,
-			       clish_ptype_preprocess_e preprocess);
+	const char *pattern, clish_ptype_method_e method,
+	clish_ptype_preprocess_e preprocess);
 /*-----------------
  * methods
  *----------------- */
 void clish_ptype_delete(clish_ptype_t * instance);
 /**
  * This is the validation method for the specified type.
- * \return 
+ * \return
  * - NULL if the validation is negative.
  * - A pointer to a string containing the validated text. NB. this
  *   may not be identical to that passed in. e.g. it may have been
@@ -103,7 +104,7 @@ char *clish_ptype_validate(const clish_ptype_t * instance, const char *text);
  * This is the translation method for the specified type. The text is
  * first validated then translated into the form which should be used
  * for variable substitutions in ACTION or VIEW_ID fields.
- * \return 
+ * \return
  * - NULL if the validation is negative.
  * - A pointer to a string containing the translated text. NB. this
  *   may not be identical to that passed in. e.g. it may have been
@@ -113,21 +114,19 @@ char *clish_ptype_translate(const clish_ptype_t * instance, const char *text);
 /**
  * This is used to perform parameter auto-completion
  */
-char *clish_ptype_word_generator(clish_ptype_t * instance,
-				 const char *text, unsigned state);
+void clish_ptype_word_generator(clish_ptype_t * instance,
+	lub_argv_t *matches, const char *text);
 void clish_ptype_dump(clish_ptype_t * instance);
 /*-----------------
- * attributes 
+ * attributes
  *----------------- */
 const char *clish_ptype__get_name(const clish_ptype_t * instance);
 const char *clish_ptype__get_text(const clish_ptype_t * instance);
 const char *clish_ptype__get_range(const clish_ptype_t * instance);
-void
-clish_ptype__set_preprocess(clish_ptype_t * instance,
-			    clish_ptype_preprocess_e preprocess);
-void
-clish_ptype__set_pattern(clish_ptype_t * instance,
-			 const char *pattern, clish_ptype_method_e method);
+void clish_ptype__set_preprocess(clish_ptype_t * instance,
+	clish_ptype_preprocess_e preprocess);
+void clish_ptype__set_pattern(clish_ptype_t * instance,
+	const char *pattern, clish_ptype_method_e method);
 void clish_ptype__set_text(clish_ptype_t * instance, const char *text);
-#endif				/* _clish_ptype_h */
+#endif	/* _clish_ptype_h */
 /** @} clish_ptype */

+ 21 - 24
clish/ptype/ptype.c

@@ -4,6 +4,7 @@
 #include "private.h"
 #include "lub/string.h"
 #include "lub/ctype.h"
+#include "lub/argv.h"
 
 #include <stdlib.h>
 #include <string.h>
@@ -211,35 +212,31 @@ clish_ptype_preprocess_e clish_ptype_preprocess_resolve(const char *name)
  *--------------------------------------------------------- */
 
 /*--------------------------------------------------------- */
-char *clish_ptype_word_generator(clish_ptype_t * this,
-				 const char *text, unsigned state)
+void clish_ptype_word_generator(clish_ptype_t * this,
+	lub_argv_t *matches, const char *text)
 {
 	char *result = NULL;
+	unsigned i = 0;
 
+	/* Another ptypes has no completions */
 	if (this->method != CLISH_PTYPE_SELECT)
-		return NULL;
-	/* first of all simply try to validate the result */
-	if (0 == state)
-		result = clish_ptype_validate(this, text);
-	if (!result) {
-		switch (this->method) {
-		case CLISH_PTYPE_SELECT:
-			if (0 == state)
-				this->last_name = 0;
-			while ((result = clish_ptype_select__get_name(this,
-					this->last_name++))) {
-				/* get the next item and check if it is a completion */
-				/* found the next completion */
-				if (result == lub_string_nocasestr(result, text))
-						break;
-				lub_string_free(result);
-			}
-			break;
-		default:
-			break;
-		}
+		return;
+
+	/* First of all simply try to validate the result */
+	result = clish_ptype_validate(this, text);
+	if (result) {
+		lub_argv_add(matches, result);
+		lub_string_free(result);
+		return;
+	}
+
+	/* Iterate possible completion */
+	while ((result = clish_ptype_select__get_name(this, i++))) {
+		/* get the next item and check if it is a completion */
+		if (result == lub_string_nocasestr(result, text))
+			lub_argv_add(matches, result);
+		lub_string_free(result);
 	}
-	return result;
 }
 
 /*--------------------------------------------------------- */

+ 0 - 2
clish/shell/module.am

@@ -10,8 +10,6 @@ libclish_la_SOURCES += \
 	clish/shell/shell_find_create_ptype.c \
 	clish/shell/shell_find_create_view.c \
 	clish/shell/shell_find_view.c \
-	clish/shell/shell_getfirst_command.c \
-	clish/shell/shell_getnext_command.c \
 	clish/shell/shell_help.c \
 	clish/shell/shell_insert_ptype.c \
 	clish/shell/shell_insert_view.c \

+ 2 - 3
clish/shell/private.h

@@ -39,9 +39,6 @@ typedef struct {
  * The context structure
  */
 struct clish_context_s {
-	clish_pargv_t *completion_pargv;
-	unsigned completion_index;
-	unsigned completion_pindex;
 	clish_shell_iterator_t iter; /* used for iterating commands */
 };
 
@@ -116,3 +113,5 @@ void clish_shell_tinyrl_history(clish_shell_t * instance, unsigned int *limit);
 tinyrl_t *clish_shell_tinyrl_new(FILE * instream,
 	FILE * outstream, unsigned stifle);
 void clish_shell_tinyrl_delete(tinyrl_t * instance);
+void clish_shell_param_generator(clish_shell_t * instance, lub_argv_t *matches,
+	const clish_command_t * cmd, const char *line, unsigned offset);

+ 52 - 116
clish/shell/shell_command_generator.c

@@ -40,144 +40,80 @@ const clish_command_t *clish_shell_find_next_completion(const clish_shell_t *
 }
 
 /*--------------------------------------------------------- */
-static char *clish_shell_param_generator(clish_shell_t * this,
-	const clish_command_t * cmd, const char *line,
-	unsigned offset, unsigned state)
+const clish_command_t *clish_shell_getfirst_command(clish_shell_t * this,
+	const char *line, clish_nspace_visibility_t field)
+{
+	clish_shell_iterator_init(&this->context.iter, field);
+
+	/* find the first command for which this is a prefix */
+	return clish_shell_getnext_command(this, line);
+}
+
+/*--------------------------------------------------------- */
+const clish_command_t *clish_shell_getnext_command(clish_shell_t * this,
+	const char *line)
+{
+	return clish_shell_find_next_completion(this, line, &this->context.iter);
+}
+
+/*--------------------------------------------------------- */
+void clish_shell_param_generator(clish_shell_t *this, lub_argv_t *matches,
+	const clish_command_t *cmd, const char *line, unsigned offset)
 {
 	char *result = NULL;
 	const char *name = clish_command__get_name(cmd);
 	char *text = lub_string_dup(&line[offset]);
-	unsigned index;
-	const clish_param_t *param = NULL;
 	clish_ptype_t *ptype;
-	unsigned idx;
-
+	unsigned idx = lub_argv_wordcount(name);
 	/* get the index of the current parameter */
-	index = lub_argv_wordcount(line) - lub_argv_wordcount(name);
+	unsigned index = lub_argv_wordcount(line) - idx;
 
 	if ((0 != index) || (line[offset - 1] == ' ')) {
-		if (0 == state) {
-			lub_argv_t *argv;
-			clish_pargv_t *pargv;
-
-			if ((0 != index) && (text[0] != '\0')) {
-				/* if there is some text for the parameter then adjust the index */
-				index--;
-			}
-			argv = lub_argv_new(line, 0);
-			idx = lub_argv_wordcount(name);
-			if (this->context.completion_pargv) {
-				clish_pargv_delete(this->context.completion_pargv);
-				this->context.completion_pargv = NULL;
-			}
-			this->context.completion_pargv = clish_pargv_create();
-			pargv = clish_pargv_create();
-			clish_pargv_parse(pargv, cmd, this->viewid, clish_command__get_paramv(cmd),
-				argv, &idx, this->context.completion_pargv, index + idx);
-			clish_pargv_delete(pargv);
-			lub_argv_delete(argv);
-			this->context.completion_index = 0;
-			this->context.completion_pindex = 0;
-		}
-
-		while ((param = clish_pargv__get_param(this->context.completion_pargv,
-			this->context.completion_index++))) {
-
+		lub_argv_t *argv = lub_argv_new(line, 0);
+		clish_pargv_t *pargv = clish_pargv_create();
+		clish_pargv_t *completion_pargv = clish_pargv_create();
+		unsigned completion_index = 0;
+		const clish_param_t *param = NULL;
+
+		/* if there is some text for the parameter then adjust the index */
+		if ((0 != index) && (text[0] != '\0'))
+			index--;
+
+		/* Parse command line to get completion pargv's */
+		clish_pargv_parse(pargv, cmd, this->viewid,
+			clish_command__get_paramv(cmd),
+			argv, &idx, completion_pargv, index + idx);
+		clish_pargv_delete(pargv);
+		lub_argv_delete(argv);
+
+		while ((param = clish_pargv__get_param(completion_pargv,
+			completion_index++))) {
 			if (param == clish_command__get_args(cmd)) {
 				/* The param is args so it has no completion */
 				result = NULL;
-			} else if (CLISH_PARAM_SUBCOMMAND ==
-				clish_param__get_mode(param)) {
-				/* The subcommand is identified by it's value */
-				result = lub_string_dup(clish_param__get_value(param));
 			} else if (CLISH_PARAM_SWITCH ==
-				   clish_param__get_mode(param)) {
+				clish_param__get_mode(param)) {
 				/* The switch has no completion string */
 				result = NULL;
+			} else if (CLISH_PARAM_SUBCOMMAND ==
+				clish_param__get_mode(param)) {
+				/* The subcommand is identified by it's value */
+				result = clish_param__get_value(param);
 			} else {
-				/* The common param. Let ptype do the work */
-				if ((ptype = clish_param__get_ptype(param))) {
-					result = clish_ptype_word_generator(ptype, text,
-						this->context.completion_pindex++);
-					if (!result)
-						this->context.completion_pindex = 0;
-					else
-						this->context.completion_index--;
-				} else {
+				/* The common PARAM. Let ptype do the work */
+				if ((ptype = clish_param__get_ptype(param)))
+					clish_ptype_word_generator(ptype,
+						matches, text);
+				else
 					result = NULL;
-				}
 			}
-
 			if (result)
-				break;
+				lub_argv_add(matches, result);
 		}
-
-	} else if (0 == state) {
-		/* simply return the command name */
-		result = lub_string_dup(clish_command__get_suffix(cmd));
+		clish_pargv_delete(completion_pargv);
 	}
 
-	if (!result) {
-		clish_pargv_delete(this->context.completion_pargv);
-		this->context.completion_pargv = NULL;
-		/* make sure we reset the line state */
-//		tinyrl_crlf(this->tinyrl);
-//		tinyrl_reset_line_state(this->tinyrl);
-//		tinyrl_completion_error_over(this->tinyrl);
-	}
 	lub_string_free(text);
-
-	return result;
-}
-
-/*--------------------------------------------------------- */
-static char *clish_shell_command_generator(clish_shell_t * this,
-	const char *line, unsigned offset, unsigned state)
-{
-	char *result = NULL;
-	const clish_command_t *cmd = NULL;
-	if (0 == state)
-		cmd = clish_shell_getfirst_command(this, line,
-			CLISH_NSPACE_COMPLETION);
-	else
-		cmd = clish_shell_getnext_command(this, line);
-	if (cmd)
-		result = lub_string_dup(clish_command__get_suffix(cmd));
-	/* keep the compiler happy */
-	offset = offset;
-
-	return result;
-}
-
-/*--------------------------------------------------------- */
-char *clish_shell_word_generator(clish_shell_t * this,
-	const char *line, unsigned offset, unsigned state)
-{
-	char *result = NULL;
-	const clish_command_t *cmd, *next = NULL;
-
-	/* try and resolve a command which is a prefix of the line */
-	cmd = clish_shell_resolve_command(this, line);
-	if (cmd) {
-		clish_shell_iterator_t iter;
-		/* see whether there is an extended extension */
-		clish_shell_iterator_init(&iter, CLISH_NSPACE_COMPLETION);
-		next = clish_shell_find_next_completion(this, line, &iter);
-	}
-	if (cmd && !next) {
-		/* this needs to be completed as a parameter */
-		result = clish_shell_param_generator(this, cmd, line, offset,
-			state);
-	} else {
-		/* this needs to be completed as a command */
-		result = clish_shell_command_generator(this, line, offset,
-			state);
-	}
-	/* reset the state from a help perspective */
-	if (0 == state)
-		this->state = SHELL_STATE_OK;
-
-	return result;
 }
 
 /*--------------------------------------------------------- */

+ 0 - 6
clish/shell/shell_delete.c

@@ -65,12 +65,6 @@ static void clish_shell_fini(clish_shell_t * this)
 		unlink(this->fifo_name);
 		lub_string_free(this->fifo_name);
 	}
-
-	/* Clear the context */
-	if (this->context.completion_pargv) {
-		clish_pargv_delete(this->context.completion_pargv);
-		this->context.completion_pargv = NULL;
-	}
 }
 
 /*--------------------------------------------------------- */

+ 0 - 16
clish/shell/shell_getfirst_command.c

@@ -1,16 +0,0 @@
-/*
- * shell_getfirst_command.c
- */
-#include "private.h"
-
-/*--------------------------------------------------------- */
-const clish_command_t *clish_shell_getfirst_command(clish_shell_t * this,
-	const char *line, clish_nspace_visibility_t field)
-{
-	clish_shell_iterator_init(&this->context.iter, field);
-
-	/* find the first command for which this is a prefix */
-	return clish_shell_getnext_command(this, line);
-}
-
-/*--------------------------------------------------------- */

+ 0 - 13
clish/shell/shell_getnext_command.c

@@ -1,13 +0,0 @@
-/*
- * shell_getnext_command.c
- */
-#include "private.h"
-
-/*--------------------------------------------------------- */
-const clish_command_t *clish_shell_getnext_command(clish_shell_t * this,
-	const char *line)
-{
-	return clish_shell_find_next_completion(this, line, &this->context.iter);
-}
-
-/*--------------------------------------------------------- */

+ 0 - 1
clish/shell/shell_new.c

@@ -76,7 +76,6 @@ clish_shell_init(clish_shell_t * this,
 	clish_param__set_hidden(this->param_interactive, BOOL_TRUE);
 
 	/* Initialize context */
-	this->context.completion_pargv = NULL;
 	clish_shell_iterator_init(&this->context.iter, CLISH_NSPACE_NONE);
 
 	/* Push non-NULL istream */

+ 48 - 25
clish/shell/shell_tinyrl.c

@@ -11,6 +11,7 @@
 #include <assert.h>
 #include <string.h>
 #include <errno.h>
+#include <ctype.h>
 
 #include "tinyrl/tinyrl.h"
 #include "tinyrl/history.h"
@@ -48,22 +49,6 @@ static bool_t clish_shell_tinyrl_key_help(tinyrl_t * this, int key)
 	return result;
 }
 
-/*-------------------------------------------------------- */
-/* Generator function for command completion.  STATE lets us
- * know whether to start from scratch; without any state
- *  (i.e. STATE == 0), then we start at the top of the list. 
- */
-/*lint -e818
-  Pointer paramter 'this' could be declared as pointing to const */
-static char *clish_shell_tinyrl_word_generator(tinyrl_t * this,
-	const char *line, unsigned offset, unsigned state)
-{
-	/* get the context */
-	context_t *context = tinyrl__get_context(this);
-
-	return clish_shell_word_generator(context->shell, line, offset, state);
-}
-
 /*lint +e818 */
 /*-------------------------------------------------------- */
 /*
@@ -285,18 +270,56 @@ static bool_t clish_shell_tinyrl_key_enter(tinyrl_t * this, int key)
 /*-------------------------------------------------------- */
 /* This is the completion function provided for CLISH */
 static tinyrl_completion_func_t clish_shell_tinyrl_completion;
-static char **clish_shell_tinyrl_completion(tinyrl_t * this,
+static char **clish_shell_tinyrl_completion(tinyrl_t * tinyrl,
 	const char *line, unsigned start, unsigned end)
 {
-	char **matches;
-
-	/* don't bother to resort to filename completion */
-	tinyrl_completion_over(this);
-	/* perform the matching */
-	matches = tinyrl_completion(this,
-		line, start, end, clish_shell_tinyrl_word_generator);
+	lub_argv_t *matches = lub_argv_new(NULL, 0);
+	context_t *context = tinyrl__get_context(tinyrl);
+	clish_shell_t *this = context->shell;
+	clish_shell_iterator_t iter;
+	const clish_command_t *cmd = NULL;
+	char *text = lub_string_dupn(line, end);
+	char **result = NULL;
+
+	/* Don't bother to resort to filename completion */
+	tinyrl_completion_over(tinyrl);
+
+	/* Search for COMMAND completions */
+	clish_shell_iterator_init(&iter, CLISH_NSPACE_COMPLETION);
+	while ((cmd = clish_shell_find_next_completion(this, text, &iter)))
+		lub_argv_add(matches, clish_command__get_suffix(cmd));
+
+	/* Try and resolve a command */
+	cmd = clish_shell_resolve_command(this, text);
+	/* Search for PARAM completion */
+	if (cmd)
+		clish_shell_param_generator(this, matches, cmd, text, start);
+
+	lub_string_free(text);
+
+	/* Matches were found */
+	if (lub_argv__get_count(matches) > 0) {
+		unsigned i;
+		char *subst = lub_string_dup(lub_argv__get_arg(matches, 0));
+		/* Find out substitution */
+		for (i = 1; i < lub_argv__get_count(matches); i++) {
+			char *p = subst;
+			const char *match = lub_argv__get_arg(matches, i);
+			size_t match_len = strlen(p);
+			/* identify the common prefix */
+			while ((tolower(*p) == tolower(*match)) && match_len--) {
+				p++;
+				match++;
+			}
+			/* Terminate the prefix string */
+			*p = '\0';
+		}
+		result = lub_argv__get_argv(matches, subst);
+		lub_string_free(subst);
+	}
+	lub_argv_delete(matches);
 
-	return matches;
+	return result;
 }
 
 /*-------------------------------------------------------- */

+ 1 - 1
konf/query/query.c

@@ -211,7 +211,7 @@ int konf_query_parse_str(konf_query_t *this, char *str)
 
 	/* Parse query */
 	res = konf_query_parse(this, str_argc, str_argv);
-	free(str_argv);
+	lub_argv__free_argv(str_argv);
 	lub_argv_delete(lub_argv);
 
 	return res;

+ 12 - 10
lub/argv.h

@@ -47,13 +47,13 @@ typedef struct lub_argv_s lub_argv_t;
  * - none
  */
 unsigned lub_argv_wordcount(
-	/** 
+	/**
          * The string to analyse
          */
-				   const char *line);
+	const char *line);
 /**
  *  This operation is used to construct an instance of this class. The client
- * species a string and an offset within that string, from which to start 
+ * species a string and an offset within that string, from which to start
  * collecting "words" to place into the vector instance.
  *
  * \pre
@@ -61,7 +61,7 @@ unsigned lub_argv_wordcount(
  *
  * \return
  * - A instance of an argument vector, which represents the words contained in
- * the provided string. 
+ * the provided string.
  * - NULL if there is insuffcient resource
  *
  * \post
@@ -69,14 +69,14 @@ unsigned lub_argv_wordcount(
  *   finished with it, by calling lub_argv_delete()
  */
 lub_argv_t *lub_argv_new(
-	/** 
+	/**
          * The string to analyse
          */
-				const char *line,
-	/** 
+	const char *line,
+	/**
          * The offset in the string to start from
          */
-				size_t offset);
+	size_t offset);
 
 void lub_argv_delete(lub_argv_t * instance);
 unsigned lub_argv__get_count(const lub_argv_t * instance);
@@ -84,8 +84,10 @@ const char *lub_argv__get_arg(const lub_argv_t * instance, unsigned index);
 size_t lub_argv__get_offset(const lub_argv_t * instance, unsigned index);
 bool_t lub_argv__get_quoted(const lub_argv_t * instance, unsigned index);
 void lub_argv__set_arg(lub_argv_t * instance, unsigned index, const char *arg);
-char **lub_argv__get_argv(const lub_argv_t * instance, char *argv0);
-const char *lub_argv__get_line(const lub_argv_t * instance);
+char **lub_argv__get_argv(const lub_argv_t * instance, const char *argv0);
+void lub_argv__free_argv(char **argv);
+char *lub_argv__get_line(const lub_argv_t * instance);
+void lub_argv_add(lub_argv_t * instance, const char *text);
 
 _END_C_DECL
 #endif				/* _lub_argv_h */

+ 2 - 2
lub/argv/argv__get_arg.c

@@ -8,9 +8,9 @@ const char *lub_argv__get_arg(const lub_argv_t * this, unsigned index)
 {
 	const char *result = NULL;
 
-	if (this->argc > index) {
+	if (this->argc > index)
 		result = this->argv[index].arg;
-	}
+
 	return result;
 }
 

+ 43 - 5
lub/argv/argv__get_argv.c

@@ -3,17 +3,42 @@
  */
 
 #include <stdlib.h>
+#include <ctype.h>
 
+#include "lub/string.h"
 #include "private.h"
 
 /*--------------------------------------------------------- */
-const char *lub_argv__get_line(const lub_argv_t * this)
+char *lub_argv__get_line(const lub_argv_t * this)
 {
-	return this->line;
+	int space = 0;
+	const char *p;
+	unsigned i;
+	char *line = NULL;
+
+	for (i = 0; i < this->argc; i++) {
+		if (i != 0)
+			lub_string_cat(&line, " ");
+		space = 0;
+		/* Search for spaces */
+		for (p = this->argv[i].arg; *p; p++) {
+			if (isspace(*p)) {
+				space = 1;
+				break;
+			}
+		}
+		if (space)
+			lub_string_cat(&line, "\"");
+		lub_string_cat(&line, this->argv[i].arg);
+		if (space)
+			lub_string_cat(&line, "\"");
+	}
+
+	return line;
 }
 
 /*--------------------------------------------------------- */
-char **lub_argv__get_argv(const lub_argv_t * this, char *argv0)
+char **lub_argv__get_argv(const lub_argv_t * this, const char *argv0)
 {
 	char **result = NULL;
 	unsigned i;
@@ -25,12 +50,25 @@ char **lub_argv__get_argv(const lub_argv_t * this, char *argv0)
 	result = malloc(sizeof(char *) * (this->argc + 1 + a));
 
 	if (argv0)
-		result[0] = argv0;
+		result[0] = lub_string_dup(argv0);
 	for (i = 0; i < this->argc; i++)
-		result[i + a] = this->argv[i].arg;
+		result[i + a] = lub_string_dup(this->argv[i].arg);
 	result[i + a] = NULL;
 
 	return result;
 }
 
 /*--------------------------------------------------------- */
+void lub_argv__free_argv(char **argv)
+{
+	unsigned i;
+
+	if (!argv)
+		return;
+
+	for (i = 0; argv[i]; i++)
+		lub_string_free(argv[i]);
+	free(argv);
+}
+
+/*--------------------------------------------------------- */

+ 2 - 2
lub/argv/argv__get_offset.c

@@ -8,9 +8,9 @@ size_t lub_argv__get_offset(const lub_argv_t * this, unsigned index)
 {
 	size_t result = 0;
 
-	if (this->argc > index) {
+	if (this->argc > index)
 		result = this->argv[index].offset;
-	}
+
 	return result;
 }
 

+ 2 - 2
lub/argv/argv__get_quoted.c

@@ -8,9 +8,9 @@ bool_t lub_argv__get_quoted(const lub_argv_t * this, unsigned index)
 {
 	bool_t result = BOOL_FALSE;
 
-	if (this->argc > index) {
+	if (this->argc > index)
 		result = this->argv[index].quoted;
-	}
+
 	return result;
 }
 

+ 1 - 4
lub/argv/argv_delete.c

@@ -10,11 +10,8 @@ static void lub_argv_fini(lub_argv_t * this)
 {
 	unsigned i;
 
-	lub_string_free(this->line);
-	this->line = NULL;
-	for (i = 0; i < this->argc; i++) {
+	for (i = 0; i < this->argc; i++)
 		lub_string_free(this->argv[i].arg);
-	}
 	free(this->argv);
 	this->argv = NULL;
 }

+ 38 - 24
lub/argv/argv_new.c

@@ -6,6 +6,7 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <assert.h>
 
 /*--------------------------------------------------------- */
 static void lub_argv_init(lub_argv_t * this, const char *line, size_t offset)
@@ -15,38 +16,36 @@ static void lub_argv_init(lub_argv_t * this, const char *line, size_t offset)
 	lub_arg_t *arg;
 	bool_t quoted;
 
-	/* Save the whole line */
-	this->line = lub_string_dup(line);
+	if (!line) {
+		this->argv = NULL;
+		this->argc = 0;
+		return;
+	}
 
 	/* first of all count the words in the line */
 	this->argc = lub_argv_wordcount(line);
 
 	/* allocate space to hold the vector */
 	arg = this->argv = malloc(sizeof(lub_arg_t) * this->argc);
+		assert(arg);
 
-	if (arg) {
-		/* then fill out the array with the words */
-		for (word = lub_argv_nextword(line, &len, &offset, &quoted);
-		     *word;
-		     word =
-		     lub_argv_nextword(word + len, &len, &offset, &quoted)) {
-			char *tmp = lub_string_dupn(word, len);
-			(*arg).arg = lub_string_decode(tmp);
-			lub_string_free(tmp);
-			(*arg).offset = offset;
-			(*arg).quoted = quoted;
+	/* then fill out the array with the words */
+	for (word = lub_argv_nextword(line, &len, &offset, &quoted);
+		*word;
+		word = lub_argv_nextword(word + len, &len, &offset, &quoted)) {
+		char *tmp = lub_string_dupn(word, len);
+		(*arg).arg = lub_string_decode(tmp);
+		lub_string_free(tmp);
+		(*arg).offset = offset;
+		(*arg).quoted = quoted;
 
-			offset += len;
+		offset += len;
 
-			if (BOOL_TRUE == quoted) {
-				len += 1;	/* account for terminating quotation mark */
-				offset += 2;	/* account for quotation marks */
-			}
-			arg++;
+		if (quoted) {
+			len += 1; /* account for terminating quotation mark */
+			offset += 2; /* account for quotation marks */
 		}
-	} else {
-		/* failed to get memory so don't pretend otherwise */
-		this->argc = 0;
+		arg++;
 	}
 }
 
@@ -56,10 +55,25 @@ lub_argv_t *lub_argv_new(const char *line, size_t offset)
 	lub_argv_t *this;
 
 	this = malloc(sizeof(lub_argv_t));
-	if (NULL != this) {
+	if (this)
 		lub_argv_init(this, line, offset);
-	}
+
 	return this;
 }
 
 /*--------------------------------------------------------- */
+void lub_argv_add(lub_argv_t * this, const char *text)
+{
+	lub_arg_t * arg;
+
+	if (!text)
+		return;
+
+	/* allocate space to hold the vector */
+	arg = realloc(this->argv, sizeof(lub_arg_t) * (this->argc + 1));
+	assert(arg);
+	this->argv = arg;
+	(this->argv[this->argc++]).arg = lub_string_dup(text);
+}
+
+/*--------------------------------------------------------- */

+ 1 - 1
lub/argv/argv_nextword.c

@@ -8,7 +8,7 @@
 #include <stddef.h>
 /*--------------------------------------------------------- */
 const char *lub_argv_nextword(const char *string,
-			      size_t * len, size_t * offset, bool_t * quoted)
+	size_t * len, size_t * offset, bool_t * quoted)
 {
 	const char *word;
 	bool_t quote = BOOL_FALSE;

+ 3 - 2
lub/argv/argv_wordcount.c

@@ -13,12 +13,13 @@ unsigned lub_argv_wordcount(const char *line)
 	bool_t quoted;
 
 	for (word = lub_argv_nextword(line, &len, &offset, &quoted);
-	     *word;
-	     word = lub_argv_nextword(word + len, &len, &offset, &quoted)) {
+		*word;
+		word = lub_argv_nextword(word + len, &len, &offset, &quoted)) {
 		/* account for the terminating quotation mark */
 		len += (BOOL_TRUE == quoted) ? 1 : 0;
 		result++;
 	}
+
 	return result;
 }
 

+ 1 - 2
lub/argv/private.h

@@ -14,7 +14,6 @@ struct lub_arg_s {
 };
 
 struct lub_argv_s {
-	char *line;
 	unsigned argc;
 	lub_arg_t *argv;
 };
@@ -22,4 +21,4 @@ struct lub_argv_s {
  * PRIVATE META FUNCTIONS
  *------------------------------------- */
 const char *lub_argv_nextword(const char *string,
-			      size_t * len, size_t * offset, bool_t * quoted);
+	size_t * len, size_t * offset, bool_t * quoted);

+ 1 - 1
lub/system/system_test.c

@@ -38,7 +38,7 @@ bool_t lub_system_argv_test(const lub_argv_t * argv)
 
 	/* Test it */
 	res = lub_system_test(str_argc, str_argv);
-	free(str_argv);
+	lub_argv__free_argv(str_argv);
 
 	return res;
 }

+ 55 - 61
tinyrl/tinyrl.c

@@ -1140,9 +1140,8 @@ tinyrl_do_complete(tinyrl_t * this, bool_t with_extensions)
 
 	/* find the start and end of the current word */
 	start = end = this->point;
-	while (start && !isspace(this->line[start - 1])) {
+	while (start && !isspace(this->line[start - 1]))
 		start--;
-	}
 
 	if (this->attempted_completion_function) {
 		this->completion_over = BOOL_FALSE;
@@ -1151,71 +1150,66 @@ tinyrl_do_complete(tinyrl_t * this, bool_t with_extensions)
 		matches = this->attempted_completion_function(this,
 			this->line, start, end);
 	}
-	if (!matches
-	    && (BOOL_FALSE == this->completion_over)) {
+	if (!matches && (BOOL_FALSE == this->completion_over)) {
 		/* insert default completion call here... */
 	}
+	if (!matches)
+		return result;
 
-	if (matches) {
-		/* identify and insert a common prefix if there is one */
-		if (0 != strncmp(matches[0], &this->line[start],
-			strlen(matches[0]))) {
-			/*
-			 * delete the original text not including 
-			 * the current insertion point character 
-			 */
-			if (this->end != end)
-				end--;
-			tinyrl_delete_text(this, start, end);
-			if (BOOL_FALSE == tinyrl_insert_text(this, matches[0])) {
-				return TINYRL_NO_MATCH;
-			}
-			completion = BOOL_TRUE;
-		}
-		for (i = 1; matches[i]; i++) {
-			/* this is just a prefix string */
-			if (0 == lub_string_nocasecmp(matches[0], matches[i]))
-				prefix = BOOL_TRUE;
+	/* identify and insert a common prefix if there is one */
+	if (0 != strncmp(matches[0], &this->line[start],
+		strlen(matches[0]))) {
+		/*
+		 * delete the original text not including
+		 * the current insertion point character
+		 */
+		if (this->end != end)
+			end--;
+		tinyrl_delete_text(this, start, end);
+		if (BOOL_FALSE == tinyrl_insert_text(this, matches[0]))
+			return TINYRL_NO_MATCH;
+		completion = BOOL_TRUE;
+	}
+	for (i = 1; matches[i]; i++) {
+		/* this is just a prefix string */
+		if (0 == lub_string_nocasecmp(matches[0], matches[i]))
+			prefix = BOOL_TRUE;
+	}
+	/* is there more than one completion? */
+	if (matches[2]) {
+		char **tmp = matches;
+		unsigned max, len;
+		max = len = 0;
+		while (*tmp) {
+			size_t size = strlen(*tmp++);
+			len++;
+			if (size > max)
+				max = size;
 		}
-		/* is there more than one completion? */
-		if (matches[2]) {
-			char **tmp = matches;
-			unsigned max, len;
-			max = len = 0;
-			while (*tmp) {
-				size_t size = strlen(*tmp++);
-				len++;
-				if (size > max) {
-					max = size;
-				}
-			}
-			if (BOOL_TRUE == completion) {
-				result = TINYRL_COMPLETED_AMBIGUOUS;
-			} else if (BOOL_TRUE == prefix) {
-				result = TINYRL_MATCH_WITH_EXTENSIONS;
-			} else {
-				result = TINYRL_AMBIGUOUS;
-			}
-			if ((BOOL_TRUE == with_extensions)
-			    || (BOOL_FALSE == prefix)) {
-				/* Either we always want to show extensions or
-				 * we haven't been able to complete the current line
-				 * and there is just a prefix, so let the user see the options
-				 */
-				tinyrl_crlf(this);
-				tinyrl_display_matches(this, matches, len, max);
-				tinyrl_reset_line_state(this);
-			}
-		} else {
-			result = completion ?
-				TINYRL_COMPLETED_MATCH : TINYRL_MATCH;
+		if (completion)
+			result = TINYRL_COMPLETED_AMBIGUOUS;
+		else if (prefix)
+			result = TINYRL_MATCH_WITH_EXTENSIONS;
+		else
+			result = TINYRL_AMBIGUOUS;
+		if (with_extensions || !prefix) {
+			/* Either we always want to show extensions or
+			 * we haven't been able to complete the current line
+			 * and there is just a prefix, so let the user see the options
+			 */
+			tinyrl_crlf(this);
+			tinyrl_display_matches(this, matches, len, max);
+			tinyrl_reset_line_state(this);
 		}
-		/* free the memory */
-		tinyrl_delete_matches(matches);
-
-		/* redisplay the line */
-		tinyrl_redisplay(this);
+	} else {
+		result = completion ?
+			TINYRL_COMPLETED_MATCH : TINYRL_MATCH;
 	}
+	/* free the memory */
+	tinyrl_delete_matches(matches);
+	/* redisplay the line */
+	tinyrl_redisplay(this);
+
 	return result;
 }