Hi Jacub and everybody
I think I've reached a first result about ticket #466, which I'm
attaching here in the form of a bazaar directive containing 5 patches.
It's the first time I use bazaar, I hope I understood how to do. Also, I
hope I respected your coding standard; please tell me if not, and I'll
re-adapt my patches.
Briefly, the current status of kconsole tab completion is:
- unique src code for all completion routines (including command tab
itself);
- enum callback infrastructure implemented;
- enum callback function implemented for commands, "call*" command
arguments and for "test" arguments.
Next step should be arguments completion for all available commands;
before proceeding, I'd like to be sure that I'm on the right direction.
Thanks for your attention!
Aurelio
On 18/02/2016 13:10, Jakub Jermář wrote:
Hi Aurelio,
On 02/18/2016 12:58 PM, Aurelio Colosimo wrote:
my name is Aurelio Colosimo, from Milan, Italy. I work as an embedded
software consultant and in my spare time I'd like to help HelenOS
project. As Martin Decky suggested me, I'd like to work on ticket #466,
"Command-specific tab completion in kernel console".
Thanks for choosing to work on HelenOS!
I'm already registered on online TRAC system, so please tell me how to
behave about it: the ticket is now owned by "Jermar", do I have to
reassign it to myself?
Yes, you can reassign the ticket to yourself, or just work on it and
assign it to yourself when the enhancement is integrated. I have no
plans to work on this anytime soon, so it's all yours if you want it.
Jakub
_______________________________________________
HelenOS-devel mailing list
[email protected]
http://lists.modry.cz/listinfo/helenos-devel
# Bazaar merge directive format 2 (Bazaar 0.90)
# revision_id: [email protected]\
# 94bjdr1n3r4t29qg
# target_branch: ../mainline-clone/
# testament_sha1: f22f8b8e51b74550b81ac07d355aeb38714d9e38
# timestamp: 2016-02-24 22:17:02 +0100
# source_branch: bzr://bzr.helenos.org/mainline
# base_revision_id: jiri@wiwaxia-20160221234818-dg3t06yezd8hyk65
#
# Begin patch
=== modified file 'kernel/generic/include/console/kconsole.h'
--- kernel/generic/include/console/kconsole.h 2012-04-02 15:52:07 +0000
+++ kernel/generic/include/console/kconsole.h 2016-02-24 19:29:26 +0000
@@ -84,6 +84,8 @@
cmd_arg_t *argv;
/** Function for printing detailed help. */
void (* help)(void);
+ /** Function for enumerating hints for arguments. */
+ const char*(*hints_enum)(const char *, const char **, void **);
} cmd_info_t;
extern bool kconsole_notify;
=== modified file 'kernel/generic/include/str.h'
--- kernel/generic/include/str.h 2012-04-02 15:52:07 +0000
+++ kernel/generic/include/str.h 2016-02-24 19:21:21 +0000
@@ -61,7 +61,7 @@
#define STR_NO_LIMIT ((size_t) -1)
/**< 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);
extern int chr_encode(wchar_t ch, char *str, size_t *offset, size_t sz);
=== modified file 'kernel/generic/include/symtab.h'
--- kernel/generic/include/symtab.h 2012-07-10 12:32:56 +0000
+++ kernel/generic/include/symtab.h 2016-02-24 20:03:02 +0000
@@ -39,7 +39,7 @@
#include <console/chardev.h>
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
=== modified file 'kernel/generic/src/console/cmd.c'
--- kernel/generic/src/console/cmd.c 2014-10-09 15:03:55 +0000
+++ kernel/generic/src/console/cmd.c 2016-02-24 20:03:02 +0000
@@ -205,7 +205,8 @@
.description = "<test> List kernel tests or run a test.",
.func = cmd_test,
.argc = 1,
- .argv = test_argv
+ .argv = test_argv,
+ .hints_enum = tests_hints_enum
};
/* Data and methods for 'bench' command. */
@@ -302,7 +303,8 @@
.description = "<function> Call function().",
.func = cmd_call0,
.argc = 1,
- .argv = &call0_argv
+ .argv = &call0_argv,
+ .hints_enum = symtab_hints_enum
};
/* Data and methods for 'mcall0' command. */
@@ -317,7 +319,8 @@
.description = "<function> Call function() on each CPU.",
.func = cmd_mcall0,
.argc = 1,
- .argv = &mcall0_argv
+ .argv = &mcall0_argv,
+ .hints_enum = symtab_hints_enum
};
/* Data and methods for 'call1' command. */
@@ -339,7 +342,8 @@
.description = "<function> <arg1> Call function(arg1).",
.func = cmd_call1,
.argc = 2,
- .argv = call1_argv
+ .argv = call1_argv,
+ .hints_enum = symtab_hints_enum
};
/* Data and methods for 'call2' command. */
@@ -366,7 +370,8 @@
.description = "<function> <arg1> <arg2> Call function(arg1, arg2).",
.func = cmd_call2,
.argc = 3,
- .argv = call2_argv
+ .argv = call2_argv,
+ .hints_enum = symtab_hints_enum
};
/* Data and methods for 'call3' command. */
@@ -399,7 +404,8 @@
.description = "<function> <arg1> <arg2> <arg3> Call function(arg1,
arg2, arg3).",
.func = cmd_call3,
.argc = 4,
- .argv = call3_argv
+ .argv = call3_argv,
+ .hints_enum = symtab_hints_enum
};
/* Data and methods for 'halt' command. */
=== modified file 'kernel/generic/src/console/kconsole.c'
--- kernel/generic/src/console/kconsole.c 2014-10-09 15:03:55 +0000
+++ kernel/generic/src/console/kconsole.c 2016-02-24 19:29:26 +0000
@@ -164,29 +164,34 @@
}
/** Try to find a command beginning with prefix */
-NO_TRACE static const char *cmdtab_search_one(const char *name,
- link_t **startpos)
+NO_TRACE static const char *cmdtab_enum(const char *name,
+ const char **h, void **ctx)
{
+ link_t **startpos = (link_t**)ctx;
size_t namelen = str_length(name);
-
+
spinlock_lock(&cmd_lock);
-
+
if (*startpos == NULL)
*startpos = cmd_list.head.next;
for (; *startpos != &cmd_list.head; *startpos = (*startpos)->next) {
cmd_info_t *hlp = list_get_instance(*startpos, cmd_info_t,
link);
-
+
const char *curname = hlp->name;
if (str_length(curname) < namelen)
continue;
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));
}
}
-
+
spinlock_unlock(&cmd_lock);
return NULL;
}
@@ -199,7 +204,8 @@
* @return Number of found matches
*
*/
-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,
+ const char*(*hints_enum)(const char *, const char **, void **))
{
const char *name = input;
@@ -211,9 +217,9 @@
*/
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;
size_t total_hints_shown = 0;
@@ -221,11 +227,10 @@
output[0] = 0;
- while ((hint = cmdtab_search_one(name, &pos))) {
+ while ((hint = hints_enum(name, NULL, &pos))) {
if ((found == 0) || (str_length(output) > str_length(hint)))
str_cpy(output, MAX_CMDLINE, hint);
- pos = pos->next;
found++;
}
@@ -242,11 +247,15 @@
if ((found > 1) && (str_length(output) != 0)) {
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;
@@ -256,12 +265,10 @@
console_prompt_more_hints(indev,
&hints_to_show);
}
}
-
- 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);
max_match_len = max_match_len_tmp;
@@ -278,6 +285,43 @@
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;
+}
+
NO_TRACE static wchar_t *clever_readline(const char *prompt, indev_t *indev)
{
printf("%s> ", prompt);
@@ -337,10 +381,15 @@
int found;
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);
}
if (found == 0)
=== modified file 'kernel/generic/src/debug/symtab.c'
--- kernel/generic/src/debug/symtab.c 2012-07-17 15:14:01 +0000
+++ kernel/generic/src/debug/symtab.c 2016-02-24 20:03:02 +0000
@@ -201,108 +201,40 @@
#endif
}
-/** 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)
+/** 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
- 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;
+ 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;
-
+
+ return NULL;
+
#else
- return 0;
+ return NULL;
#endif
}
=== modified file 'kernel/test/test.c'
--- kernel/test/test.c 2012-07-27 13:45:23 +0000
+++ kernel/test/test.c 2016-02-24 20:35:29 +0000
@@ -33,6 +33,7 @@
*/
#include <test.h>
+#include <str.h>
bool test_quiet;
@@ -67,5 +68,31 @@
}
};
+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;
+}
+
/** @}
*/
=== modified file 'kernel/test/test.h'
--- kernel/test/test.h 2012-07-27 13:45:23 +0000
+++ kernel/test/test.h 2016-02-24 20:35:29 +0000
@@ -84,6 +84,8 @@
extern test_t tests[];
+extern const char* tests_hints_enum(const char *, const char **, void **);
+
#endif
/** @}
# Begin bundle
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
_______________________________________________
HelenOS-devel mailing list
[email protected]
http://lists.modry.cz/listinfo/helenos-devel