Index: kernel/generic/include/console/kconsole.h
===================================================================
--- kernel/generic/include/console/kconsole.h	(revision df425da2dc81800838072b02859b6344366da889)
+++ kernel/generic/include/console/kconsole.h	(revision d4d8255695d912194c2d1bb169fb048490d6968e)
@@ -43,4 +43,7 @@
 #define KCONSOLE_HISTORY  10
 
+/** Callback to be used to enum hints for cmd tab completion. */
+typedef const char *(*hints_enum_func_t)(const char *, const char **, void **);
+
 typedef enum {
 	ARG_TYPE_INVALID = 0,
@@ -85,4 +88,6 @@
 	/** Function for printing detailed help. */
 	void (* help)(void);
+	/** Function for enumerating hints for arguments. */
+	hints_enum_func_t hints_enum;
 } cmd_info_t;
 
@@ -100,4 +105,5 @@
 
 extern bool cmd_register(cmd_info_t *cmd);
+extern const char *cmdtab_enum(const char *name, const char **h, void **ctx);
 
 #endif
Index: kernel/generic/include/str.h
===================================================================
--- kernel/generic/include/str.h	(revision df425da2dc81800838072b02859b6344366da889)
+++ kernel/generic/include/str.h	(revision d4d8255695d912194c2d1bb169fb048490d6968e)
@@ -62,5 +62,5 @@
 
 /**< Maximum size of a string containing cnt characters */
-#define STR_BOUNDS(cnt)  (cnt << 2)
+#define STR_BOUNDS(cnt)  ((cnt) << 2)
 
 extern wchar_t str_decode(const char *str, size_t *offset, size_t sz);
Index: kernel/generic/include/symtab.h
===================================================================
--- kernel/generic/include/symtab.h	(revision df425da2dc81800838072b02859b6344366da889)
+++ kernel/generic/include/symtab.h	(revision d4d8255695d912194c2d1bb169fb048490d6968e)
@@ -40,5 +40,5 @@
 
 extern void symtab_print_search(const char *);
-extern int symtab_compl(char *, size_t, indev_t *);
+extern const char* symtab_hints_enum(const char *, const char **, void **);
 
 #endif
Index: kernel/generic/src/console/cmd.c
===================================================================
--- kernel/generic/src/console/cmd.c	(revision df425da2dc81800838072b02859b6344366da889)
+++ kernel/generic/src/console/cmd.c	(revision d4d8255695d912194c2d1bb169fb048490d6968e)
@@ -206,5 +206,6 @@
 	.func = cmd_test,
 	.argc = 1,
-	.argv = test_argv
+	.argv = test_argv,
+	.hints_enum = tests_hints_enum
 };
 
@@ -246,5 +247,6 @@
 	.func = cmd_desc,
 	.argc = 1,
-	.argv = &desc_argv
+	.argv = &desc_argv,
+	.hints_enum = cmdtab_enum
 };
 
@@ -262,5 +264,6 @@
 	.func = cmd_symaddr,
 	.argc = 1,
-	.argv = &symaddr_argv
+	.argv = &symaddr_argv,
+	.hints_enum = symtab_hints_enum,
 };
 
@@ -303,5 +306,6 @@
 	.func = cmd_call0,
 	.argc = 1,
-	.argv = &call0_argv
+	.argv = &call0_argv,
+	.hints_enum = symtab_hints_enum
 };
 
@@ -318,5 +322,6 @@
 	.func = cmd_mcall0,
 	.argc = 1,
-	.argv = &mcall0_argv
+	.argv = &mcall0_argv,
+	.hints_enum = symtab_hints_enum
 };
 
@@ -340,5 +345,6 @@
 	.func = cmd_call1,
 	.argc = 2,
-	.argv = call1_argv
+	.argv = call1_argv,
+	.hints_enum = symtab_hints_enum
 };
 
@@ -367,5 +373,6 @@
 	.func = cmd_call2,
 	.argc = 3,
-	.argv = call2_argv
+	.argv = call2_argv,
+	.hints_enum = symtab_hints_enum
 };
 
@@ -400,5 +407,6 @@
 	.func = cmd_call3,
 	.argc = 4,
-	.argv = call3_argv
+	.argv = call3_argv,
+	.hints_enum = symtab_hints_enum
 };
 
Index: kernel/generic/src/console/kconsole.c
===================================================================
--- kernel/generic/src/console/kconsole.c	(revision df425da2dc81800838072b02859b6344366da889)
+++ kernel/generic/src/console/kconsole.c	(revision d4d8255695d912194c2d1bb169fb048490d6968e)
@@ -165,7 +165,7 @@
 
 /** Try to find a command beginning with prefix */
-NO_TRACE static const char *cmdtab_search_one(const char *name,
-    link_t **startpos)
-{
+const char *cmdtab_enum(const char *name, const char **h, void **ctx)
+{
+	link_t **startpos = (link_t**)ctx;
 	size_t namelen = str_length(name);
 	
@@ -183,4 +183,8 @@
 		
 		if (str_lcmp(curname, name, namelen) == 0) {
+			*startpos = (*startpos)->next;
+			if (h) {
+				*h = hlp->description;
+			}
 			spinlock_unlock(&cmd_lock);
 			return (curname + str_lsize(curname, namelen));
@@ -200,5 +204,6 @@
  *
  */
-NO_TRACE static int cmdtab_compl(char *input, size_t size, indev_t *indev)
+NO_TRACE static int cmdtab_compl(char *input, size_t size, indev_t *indev,
+    hints_enum_func_t hints_enum)
 {
 	const char *name = input;
@@ -212,7 +217,7 @@
 	size_t max_match_len = size;
 	size_t max_match_len_tmp = size;
-	size_t input_len = str_length(input);
-	link_t *pos = NULL;
+	void *pos = NULL;
 	const char *hint;
+	const char *help;
 	char *output = malloc(MAX_CMDLINE, 0);
 	size_t hints_to_show = MAX_TAB_HINTS - 1;
@@ -222,9 +227,8 @@
 	output[0] = 0;
 	
-	while ((hint = cmdtab_search_one(name, &pos))) {
-		if ((found == 0) || (str_length(output) > str_length(hint)))
+	while ((hint = hints_enum(name, NULL, &pos))) {
+		if ((found == 0) || (str_length(hint) > str_length(output)))
 			str_cpy(output, MAX_CMDLINE, hint);
 		
-		pos = pos->next;
 		found++;
 	}
@@ -243,9 +247,13 @@
 		printf("\n");
 		pos = NULL;
-		while (cmdtab_search_one(name, &pos)) {
-			cmd_info_t *hlp = list_get_instance(pos, cmd_info_t, link);
+		while ((hint = hints_enum(name, &help, &pos))) {
 			
 			if (continue_showing_hints) {
-				printf("%s (%s)\n", hlp->name, hlp->description);
+				
+				if (help)
+					printf("%s%s (%s)\n", name, hint, help);
+				else
+					printf("%s%s\n", name, hint);
+				
 				--hints_to_show;
 				++total_hints_shown;
@@ -258,9 +266,7 @@
 			}
 			
-			pos = pos->next;
-			
 			for (max_match_len_tmp = 0;
 			    (output[max_match_len_tmp] ==
-			    hlp->name[input_len + max_match_len_tmp]) &&
+			    hint[max_match_len_tmp]) &&
 			    (max_match_len_tmp < max_match_len); ++max_match_len_tmp);
 			
@@ -277,4 +283,41 @@
 	free(output);
 	return found;
+}
+
+NO_TRACE static cmd_info_t *parse_cmd(const wchar_t *cmdline)
+{
+	size_t start = 0;
+	size_t end;
+	char *tmp;
+	
+	while (isspace(cmdline[start]))
+		start++;
+	end = start + 1;
+	while (!isspace(cmdline[end]))
+		end++;
+	
+	tmp = malloc(STR_BOUNDS(end - start + 1), 0);
+	
+	wstr_to_str(tmp, end - start + 1, &cmdline[start]);
+	
+	spinlock_lock(&cmd_lock);
+	
+	list_foreach(cmd_list, link, cmd_info_t, hlp) {
+		spinlock_lock(&hlp->lock);
+		
+		if (str_cmp(hlp->name, tmp) == 0) {
+			spinlock_unlock(&hlp->lock);
+			spinlock_unlock(&cmd_lock);
+			free(tmp);
+			return hlp;
+		}
+		
+		spinlock_unlock(&hlp->lock);
+	}
+	
+	free(tmp);
+	spinlock_unlock(&cmd_lock);
+	
+	return NULL;
 }
 
@@ -338,8 +381,13 @@
 			if (beg == 0) {
 				/* Command completion */
-				found = cmdtab_compl(tmp, STR_BOUNDS(MAX_CMDLINE), indev);
+				found = cmdtab_compl(tmp, STR_BOUNDS(MAX_CMDLINE), indev,
+				    cmdtab_enum);
 			} else {
-				/* Symbol completion */
-				found = symtab_compl(tmp, STR_BOUNDS(MAX_CMDLINE), indev);
+				/* Arguments completion */
+				cmd_info_t *cmd = parse_cmd(current);
+				if (!cmd || !cmd->hints_enum)
+					continue;
+				found = cmdtab_compl(tmp, STR_BOUNDS(MAX_CMDLINE), indev,
+				    cmd->hints_enum);
 			}
 			
Index: kernel/generic/src/debug/symtab.c
===================================================================
--- kernel/generic/src/debug/symtab.c	(revision df425da2dc81800838072b02859b6344366da889)
+++ kernel/generic/src/debug/symtab.c	(revision d4d8255695d912194c2d1bb169fb048490d6968e)
@@ -202,106 +202,38 @@
 }
 
-/** Symtab completion
- *
- * @param input Search string, completes to symbol name
- * @param size  Input buffer size
- *
- * @return 0 - nothing found, 1 - success, >1 print duplicates
- *
- */
-int symtab_compl(char *input, size_t size, indev_t *indev)
-{
-#ifdef CONFIG_SYMTAB
-	const char *name = input;
-	
-	/* Allow completion of pointers */
-	if ((name[0] == '*') || (name[0] == '&'))
-		name++;
-	
-	/* Do not print all symbols */
-	if (str_length(name) == 0)
-		return 0;
-	
-	size_t found = 0;
-	size_t pos = 0;
-	const char *hint;
-	char output[MAX_SYMBOL_NAME];
-	
-	/*
-	 * Maximum Match Length: Length of longest matching common substring in
-	 * case more than one match is found.
-	 */
-	size_t max_match_len = size;
-	size_t max_match_len_tmp = size;
-	size_t input_len = str_length(input);
-	char *sym_name;
-	size_t hints_to_show = MAX_TAB_HINTS - 1;
-	size_t total_hints_shown = 0;
-	bool continue_showing_hints = true;
-	
-	output[0] = 0;
-	
-	while ((hint = symtab_search_one(name, &pos)))
-		pos++;
-	
-	pos = 0;
-	
-	while ((hint = symtab_search_one(name, &pos))) {
-		if ((found == 0) || (str_length(output) > str_length(hint)))
-			str_cpy(output, MAX_SYMBOL_NAME, hint);
-		
-		pos++;
-		found++;
-	}
-	
-	/*
-	 * If the number of possible completions is more than MAX_TAB_HINTS,
-	 * ask the user whether to display them or not.
-	 */
-	if (found > MAX_TAB_HINTS) {
-		printf("\n");
-		continue_showing_hints =
-		    console_prompt_display_all_hints(indev, found);
-	}
-	
-	if ((found > 1) && (str_length(output) != 0)) {
-		printf("\n");
-		pos = 0;
-		while (symtab_search_one(name, &pos)) {
-			sym_name = symbol_table[pos].symbol_name;
-			pos++;
-			
-			if (continue_showing_hints) {
-				/* We are still showing hints */
-				printf("%s\n", sym_name);
-				--hints_to_show;
-				++total_hints_shown;
-				
-				if ((hints_to_show == 0) && (total_hints_shown != found)) {
-					/* Ask the user to continue */
-					continue_showing_hints =
-					    console_prompt_more_hints(indev, &hints_to_show);
-				}
-			}
-			
-			for (max_match_len_tmp = 0;
-			    (output[max_match_len_tmp] ==
-			    sym_name[input_len + max_match_len_tmp]) &&
-			    (max_match_len_tmp < max_match_len); ++max_match_len_tmp);
-			
-			max_match_len = max_match_len_tmp;
+/** Symtab completion enum, see kernel/generic/include/kconsole.h */
+const char* symtab_hints_enum(const char *input, const char **help,
+    void **ctx)
+{
+#ifdef CONFIG_SYMTAB
+	size_t len = str_length(input);
+	struct symtab_entry **entry = (struct symtab_entry**)ctx;
+	
+	if (*entry == NULL)
+		*entry = symbol_table;
+	
+	for (; (*entry)->address_le; (*entry)++) {
+		const char *curname = (*entry)->symbol_name;
+		
+		/* Find a ':' in curname */
+		const char *colon = str_chr(curname, ':');
+		if (colon == NULL)
+			continue;
+		
+		if (str_length(curname) < len)
+			continue;
+		
+		if (str_lcmp(input, curname, len) == 0) {
+			(*entry)++;
+			if (help)
+				*help = NULL;
+			return (curname + str_lsize(curname, len));
 		}
-		
-		/* Keep only the characters common in all completions */
-		output[max_match_len] = 0;
-	}
-	
-	if (found > 0)
-		str_cpy(input, size, output);
-	
-	return found;
-	
-#else
-	return 0;
+	}
+	
+	return NULL;
+	
+#else
+	return NULL;
 #endif
 }
Index: kernel/test/test.c
===================================================================
--- kernel/test/test.c	(revision df425da2dc81800838072b02859b6344366da889)
+++ kernel/test/test.c	(revision d4d8255695d912194c2d1bb169fb048490d6968e)
@@ -34,4 +34,5 @@
 
 #include <test.h>
+#include <str.h>
 
 bool test_quiet;
@@ -68,4 +69,30 @@
 };
 
+const char* tests_hints_enum(const char *input, const char **help,
+    void **ctx)
+{
+	size_t len = str_length(input);
+	test_t **test = (test_t**)ctx;
+	
+	if (*test == NULL)
+		*test = tests;
+	
+	for (; (*test)->name; (*test)++) {
+		const char *curname = (*test)->name;
+		
+		if (str_length(curname) < len)
+			continue;
+		
+		if (str_lcmp(input, curname, len) == 0) {
+			(*test)++;
+			if (help)
+				*help = (*test)->desc;
+			return (curname + str_lsize(curname, len));
+		}
+	}
+	
+	return NULL;
+}
+
 /** @}
  */
Index: kernel/test/test.h
===================================================================
--- kernel/test/test.h	(revision df425da2dc81800838072b02859b6344366da889)
+++ kernel/test/test.h	(revision d4d8255695d912194c2d1bb169fb048490d6968e)
@@ -85,4 +85,6 @@
 extern test_t tests[];
 
+extern const char* tests_hints_enum(const char *, const char **, void **);
+
 #endif
 
