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

Reply via email to