diff options
Diffstat (limited to 'tools/lint/completion.c')
-rw-r--r-- | tools/lint/completion.c | 208 |
1 files changed, 171 insertions, 37 deletions
diff --git a/tools/lint/completion.c b/tools/lint/completion.c index 9843816..67c6b68 100644 --- a/tools/lint/completion.c +++ b/tools/lint/completion.c @@ -43,14 +43,18 @@ cmd_completion_add_match(const char *match, char ***matches, unsigned int *match { void *p; - ++(*match_count); - p = realloc(*matches, *match_count * sizeof **matches); + p = realloc(*matches, (*match_count + 1) * sizeof **matches); if (!p) { - YLMSG_E("Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno)); + YLMSG_E("Memory allocation failed (%s:%d, %s).", __FILE__, __LINE__, strerror(errno)); return; } *matches = p; - (*matches)[*match_count - 1] = strdup(match); + (*matches)[*match_count] = strdup(match); + if (!((*matches)[*match_count])) { + YLMSG_E("Memory allocation failed (%s:%d, %s).", __FILE__, __LINE__, strerror(errno)); + return; + } + ++(*match_count); } /** @@ -76,6 +80,34 @@ get_cmd_completion(const char *hint, char ***matches, unsigned int *match_count) } /** + * @brief Provides completion for arguments. + * + * @param[in] hint User input. + * @param[in] args Array of all possible arguments. The last element must be NULL. + * @param[out] matches Matches provided to the user as a completion hint. + * @param[out] match_count Number of matches. + */ +static void +get_arg_completion(const char *hint, const char **args, char ***matches, unsigned int *match_count) +{ + int i; + + *match_count = 0; + *matches = NULL; + + for (i = 0; args[i]; i++) { + if (!strncmp(hint, args[i], strlen(hint))) { + cmd_completion_add_match(args[i], matches, match_count); + } + } + if (*match_count == 0) { + for (i = 0; args[i]; i++) { + cmd_completion_add_match(args[i], matches, match_count); + } + } +} + +/** * @brief Provides completion for module names. * * @param[in] hint User input. @@ -108,21 +140,21 @@ get_model_completion(const char *hint, char ***matches, unsigned int *match_coun /** * @brief Add all child nodes of a single node to the completion hint. * - * @param[in] last_node Node of which children will be added to the hint. - * @param matches[out] Matches provided to the user as a completion hint. - * @param match_count[out] Number of matches. + * @param[in] parent Node of which children will be added to the hint. + * @param[out] matches Matches provided to the user as a completion hint. + * @param[out] match_count Number of matches. */ static void -single_hint_add_children(const struct lysc_node *last_node, char ***matches, unsigned int *match_count) +single_hint_add_children(const struct lysc_node *parent, char ***matches, unsigned int *match_count) { const struct lysc_node *node = NULL; char *match; - if (!last_node) { + if (!parent) { return; } - while ((node = lys_getnext(node, last_node, NULL, LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHCHOICE))) { + while ((node = lys_getnext(node, parent, NULL, LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHCHOICE))) { match = lysc_path(node, LYSC_PATH_LOG, NULL, 0); cmd_completion_add_match(match, matches, match_count); free(match); @@ -157,13 +189,13 @@ add_all_children_nodes(const struct lysc_module *module, const struct lysc_node if (parent && (node->module != parent->module)) { /* augmented node */ if (asprintf(&node_name, "%s:%s", node->module->name, node->name) == -1) { - YLMSG_E("Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno)); + YLMSG_E("Memory allocation failed (%s:%d, %s).", __FILE__, __LINE__, strerror(errno)); break; } } else { node_name = strdup(node->name); if (!node_name) { - YLMSG_E("Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno)); + YLMSG_E("Memory allocation failed (%s:%d, %s).", __FILE__, __LINE__, strerror(errno)); break; } } @@ -229,7 +261,7 @@ get_schema_completion(const char *hint, char ***matches, unsigned int *match_cou /* module name known */ module_name = strndup(start, end - start); if (!module_name) { - YLMSG_E("Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno)); + YLMSG_E("Memory allocation failed (%s:%d, %s).", __FILE__, __LINE__, strerror(errno)); rc = 1; goto cleanup; } @@ -255,7 +287,7 @@ get_schema_completion(const char *hint, char ***matches, unsigned int *match_cou /* get rid of stuff after the last '/' to obtain the parent node */ path = strndup(hint, start - hint); if (!path) { - YLMSG_E("Memory allocation failed (%s:%d, %s)", __FILE__, __LINE__, strerror(errno)); + YLMSG_E("Memory allocation failed (%s:%d, %s).", __FILE__, __LINE__, strerror(errno)); rc = 1; goto cleanup; } @@ -277,6 +309,90 @@ cleanup: } /** + * @brief Get all possible argument hints for option. + * + * @param[in] hint User input. + * @param[out] matches Matches provided to the user as a completion hint. + * @param[out] match_count Number of matches. + */ +static void +get_print_format_arg(const char *hint, char ***matches, unsigned int *match_count) +{ + const char *args[] = {"yang", "yin", "tree", "info", NULL}; + + get_arg_completion(hint, args, matches, match_count); +} + +/** + * @copydoc get_print_format_arg + */ +static void +get_data_type_arg(const char *hint, char ***matches, unsigned int *match_count) +{ + const char *args[] = {"data", "config", "get", "getconfig", "edit", "rpc", "reply", "notif", NULL}; + + get_arg_completion(hint, args, matches, match_count); +} + +/** + * @copydoc get_print_format_arg + */ +static void +get_data_in_format_arg(const char *hint, char ***matches, unsigned int *match_count) +{ + const char *args[] = {"xml", "json", "lyb", NULL}; + + get_arg_completion(hint, args, matches, match_count); +} + +/** + * @copydoc get_print_format_arg + */ +static void +get_data_default_arg(const char *hint, char ***matches, unsigned int *match_count) +{ + const char *args[] = {"all", "all-tagged", "trim", "implicit-tagged", NULL}; + + get_arg_completion(hint, args, matches, match_count); +} + +/** + * @copydoc get_print_format_arg + */ +static void +get_list_format_arg(const char *hint, char ***matches, unsigned int *match_count) +{ + const char *args[] = {"xml", "json", NULL}; + + get_arg_completion(hint, args, matches, match_count); +} + +/** + * @copydoc get_print_format_arg + */ +static void +get_verb_arg(const char *hint, char ***matches, unsigned int *match_count) +{ + const char *args[] = {"error", "warning", "verbose", "debug", NULL}; + + get_arg_completion(hint, args, matches, match_count); +} + +#ifndef NDEBUG +/** + * @copydoc get_print_format_arg + */ +static void +get_debug_arg(const char *hint, char ***matches, unsigned int *match_count) +{ + const char *args[] = {"dict", "xpath", "dep-sets", NULL}; + + get_arg_completion(hint, args, matches, match_count); +} + +#endif + +/** * @brief Get the string before the hint, which autocompletion is for. * * @param[in] buf Complete user input. @@ -315,22 +431,37 @@ void complete_cmd(const char *buf, const char *hint, linenoiseCompletions *lc) { struct autocomplete { - const char *cmd; /**< command */ - const char *opt; /**< optional option */ - int last_opt; /**< whether to autocomplete even if an option is last in the hint */ - + enum COMMAND_INDEX ci; /**< command index to global variable 'commands' */ + const char *opt; /**< optional option */ void (*ln_cb)(const char *, const char *, linenoiseCompletions *); /**< linenoise callback to call */ void (*yl_cb)(const char *, char ***, unsigned int *); /**< yanglint callback to call */ } ac[] = { - {"add", NULL, 1, linenoisePathCompletion, NULL}, - {"searchpath", NULL, 0, linenoisePathCompletion, NULL}, - {"data", NULL, 0, linenoisePathCompletion, NULL}, - {"print", NULL, 0, NULL, get_model_completion}, - {"feature", NULL, 0, NULL, get_model_completion}, - {"print", "-P", 1, NULL, get_schema_completion}, + {CMD_ADD, NULL, linenoisePathCompletion, NULL}, + {CMD_PRINT, "-f", NULL, get_print_format_arg}, + {CMD_PRINT, "-P", NULL, get_schema_completion}, + {CMD_PRINT, "-o", linenoisePathCompletion, NULL}, + {CMD_PRINT, NULL, NULL, get_model_completion}, + {CMD_SEARCHPATH, NULL, linenoisePathCompletion, NULL}, + {CMD_EXTDATA, NULL, linenoisePathCompletion, NULL}, + {CMD_CLEAR, "-Y", linenoisePathCompletion, NULL}, + {CMD_DATA, "-t", NULL, get_data_type_arg}, + {CMD_DATA, "-O", linenoisePathCompletion, NULL}, + {CMD_DATA, "-R", linenoisePathCompletion, NULL}, + {CMD_DATA, "-f", NULL, get_data_in_format_arg}, + {CMD_DATA, "-F", NULL, get_data_in_format_arg}, + {CMD_DATA, "-d", NULL, get_data_default_arg}, + {CMD_DATA, "-o", linenoisePathCompletion, NULL}, + {CMD_DATA, NULL, linenoisePathCompletion, NULL}, + {CMD_LIST, NULL, NULL, get_list_format_arg}, + {CMD_FEATURE, NULL, NULL, get_model_completion}, + {CMD_VERB, NULL, NULL, get_verb_arg}, +#ifndef NDEBUG + {CMD_DEBUG, NULL, NULL, get_debug_arg}, +#endif }; - size_t cmd_len; - const char *last; + size_t name_len; + const char *last, *name, *getoptstr; + char opt[3] = {'\0', ':', '\0'}; char **matches = NULL; unsigned int match_count = 0, i; @@ -340,24 +471,27 @@ complete_cmd(const char *buf, const char *hint, linenoiseCompletions *lc) } else { for (i = 0; i < (sizeof ac / sizeof *ac); ++i) { - cmd_len = strlen(ac[i].cmd); - if (strncmp(buf, ac[i].cmd, cmd_len) || (buf[cmd_len] != ' ')) { + /* Find the right command. */ + name = commands[ac[i].ci].name; + name_len = strlen(name); + if (strncmp(buf, name, name_len) || (buf[name_len] != ' ')) { /* not this command */ continue; } + /* Select based on the right option. */ last = get_last_str(buf, hint); - if (ac[i].opt && strncmp(ac[i].opt, last, strlen(ac[i].opt))) { - /* autocompletion for (another) option */ + opt[0] = (last[0] == '-') && last[1] ? last[1] : '\0'; + getoptstr = commands[ac[i].ci].optstring; + if (!ac[i].opt && opt[0] && strstr(getoptstr, opt)) { + /* completion for the argument must be defined */ continue; - } - if (!ac[i].last_opt && (last[0] == '-')) { - /* autocompletion for the command, not an option */ + } else if (ac[i].opt && opt[0] && strncmp(ac[i].opt, last, strlen(ac[i].opt))) { + /* completion for (another) option */ + continue; + } else if (ac[i].opt && !opt[0]) { + /* completion is defined for option */ continue; - } - if ((last != buf) && (last[0] != '-')) { - /* autocompleted */ - return; } /* callback */ |