You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ma...@apache.org on 2017/05/17 17:14:44 UTC
[4/8] incubator-mynewt-core git commit: sys/shell: add support for
tab completion
sys/shell: add support for tab completion
Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/038dc7f4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/038dc7f4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/038dc7f4
Branch: refs/heads/master
Commit: 038dc7f4cc95805eac9684d9be011d24b8ad3fc4
Parents: 98eebe0
Author: Michał Narajowski <mi...@codecoup.pl>
Authored: Wed May 3 10:59:23 2017 +0200
Committer: Michał Narajowski <mi...@codecoup.pl>
Committed: Wed May 3 12:12:04 2017 +0200
----------------------------------------------------------------------
sys/shell/src/shell.c | 405 +++++++++++++++++++++++++++++++++++++++++++++
sys/shell/syscfg.yml | 3 +
2 files changed, 408 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/038dc7f4/sys/shell/src/shell.c
----------------------------------------------------------------------
diff --git a/sys/shell/src/shell.c b/sys/shell/src/shell.c
index fa5a8f5..d186aa7 100644
--- a/sys/shell/src/shell.c
+++ b/sys/shell/src/shell.c
@@ -401,6 +401,407 @@ shell(struct os_event *ev)
os_eventq_put(&avail_queue, ev);
}
+#if MYNEWT_VAL(SHELL_COMPLETION)
+static void
+print_command_params(const int module, const int command)
+{
+ const struct shell_module *shell_module = &shell_modules[module];
+ const struct shell_cmd *shell_cmd = &shell_module->commands[command];
+ int i;
+
+ if (!(shell_cmd->help && shell_cmd->help->params)) {
+ return;
+ }
+
+ for (i = 0; shell_cmd->help->params[i].param_name; i++) {
+ console_printf("%-30s%s\n", shell_cmd->help->params[i].param_name,
+ shell_cmd->help->params[i].help);
+ }
+}
+
+static int
+get_command_from_module(const char *command, int len, int module)
+{
+ int i;
+ const struct shell_module *shell_module;
+
+ shell_module = &shell_modules[module];
+ for (i = 0; shell_module->commands[i].sc_cmd; i++) {
+ if (!strncmp(command, shell_module->commands[i].sc_cmd, len)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+static int
+get_token(char **cur, int *null_terminated)
+{
+ char *str = *cur;
+
+ *null_terminated = 0;
+ /* remove ' ' at the beginning */
+ while (*str && *str == ' ') {
+ str++;
+ }
+
+ if (!str) {
+ *null_terminated = 1;
+ return 0;
+ }
+
+ *cur = str;
+ str = strchr(str, ' ');
+
+ if (str == NULL) {
+ *null_terminated = 1;
+ return strlen(*cur);
+ }
+
+ return str - *cur;
+}
+
+static int
+get_last_token(char **cur)
+{
+ *cur = strrchr(*cur, ' ');
+ if (*cur == NULL) {
+ return 0;
+ }
+ (*cur)++;
+ return strlen(*cur);
+}
+
+static int
+complete_param(char *line, uint8_t len, const char *param_prefix,
+ int param_len, int module_idx, int command_idx)
+{
+ const char *first_match = NULL;
+ int i, common_chars = -1;
+ const struct shell_cmd *command;
+
+ command = &shell_modules[module_idx].commands[command_idx];
+
+ if (!(command->help && command->help->params)) {
+ return 0;
+ }
+
+ for (i = 0; command->help->params[i].param_name; i++) {
+ int j;
+
+ if (strncmp(param_prefix,
+ command->help->params[i].param_name, param_len)) {
+ continue;
+ }
+
+ if (!first_match) {
+ first_match = command->help->params[i].param_name;
+ continue;
+ }
+
+ /* more commands match, print first match */
+ if (first_match && (common_chars < 0)) {
+ console_printf("\n");
+ console_printf("%s\n", first_match);
+ common_chars = strlen(first_match);
+ }
+
+ /* cut common part of matching names */
+ for (j = 0; j < common_chars; j++) {
+ if (first_match[j] != command->help->params[i].param_name[j]) {
+ break;
+ }
+ }
+
+ common_chars = j;
+
+ console_printf("%s\n", command->help->params[i].param_name);
+ }
+
+ /* no match, do nothing */
+ if (!first_match) {
+ return 0;
+ }
+
+ if (common_chars >= 0) {
+ /* multiple match, restore prompt */
+ console_printf("%s", get_prompt());
+ console_printf("%s", line);
+ } else {
+ common_chars = strlen(first_match);
+ }
+
+ /* complete common part */
+ for (i = param_len; i < common_chars; i++) {
+ console_printf("%c", first_match[i]);
+ line[len++] = first_match[i];
+ }
+
+ return common_chars - param_len;
+}
+
+static int
+complete_command(char *line, uint8_t len, char *command_prefix,
+ int command_len, int module_idx)
+{
+ const char *first_match = NULL;
+ int i, common_chars = -1, space = 0;
+ const struct shell_module *module;
+
+ module = &shell_modules[module_idx];
+
+ for (i = 0; module->commands[i].sc_cmd; i++) {
+ int j;
+
+ if (strncmp(command_prefix,
+ module->commands[i].sc_cmd, command_len)) {
+ continue;
+ }
+
+ if (!first_match) {
+ first_match = module->commands[i].sc_cmd;
+ continue;
+ }
+
+ /* more commands match, print first match */
+ if (first_match && (common_chars < 0)) {
+ console_printf("\n");
+ console_printf("%s\n", first_match);
+ common_chars = strlen(first_match);
+ }
+
+ /* cut common part of matching names */
+ for (j = 0; j < common_chars; j++) {
+ if (first_match[j] != module->commands[i].sc_cmd[j]) {
+ break;
+ }
+ }
+
+ common_chars = j;
+
+ console_printf("%s\n", module->commands[i].sc_cmd);
+ }
+
+ /* no match, do nothing */
+ if (!first_match) {
+ return 0;
+ }
+
+ if (common_chars >= 0) {
+ /* multiple match, restore prompt */
+ console_printf("%s", get_prompt());
+ console_printf("%s", line);
+ } else {
+ common_chars = strlen(first_match);
+ space = 1;
+ }
+
+ /* complete common part */
+ for (i = command_len; i < common_chars; i++) {
+ console_printf("%c", first_match[i]);
+ line[len++] = first_match[i];
+ }
+
+ /* for convenience add space after command */
+ if (space) {
+ console_printf(" ");
+ line[len] = ' ';
+ }
+
+ return common_chars - command_len + space;
+}
+
+static int
+complete_module(char *line, int len, char *module_prefix, int module_len)
+{
+ int i;
+ const char *first_match = NULL;
+ int common_chars = -1, space = 0;
+
+ if (!module_len) {
+ console_printf("\n");
+ for (i = 0; i < num_of_shell_entities; i++) {
+ console_printf("%s\n", shell_modules[i].module_name);
+ }
+ console_printf("%s", get_prompt());
+ console_printf("%s", line);
+ return 0;
+ }
+
+ for (i = 0; i < num_of_shell_entities; i++) {
+ int j;
+
+ if (strncmp(module_prefix,
+ shell_modules[i].module_name,
+ module_len)) {
+ continue;
+ }
+
+ if (!first_match) {
+ first_match = shell_modules[i].module_name;
+ continue;
+ }
+
+ /* more commands match, print first match */
+ if (first_match && (common_chars < 0)) {
+ console_printf("\n");
+ console_printf("%s\n", first_match);
+ common_chars = strlen(first_match);
+ }
+
+ /* cut common part of matching names */
+ for (j = 0; j < common_chars; j++) {
+ if (first_match[j] != shell_modules[i].module_name[j]) {
+ break;
+ }
+ }
+
+ common_chars = j;
+
+ console_printf("%s\n", shell_modules[i].module_name);
+ }
+
+ /* no match, do nothing */
+ if (!first_match) {
+ return 0;
+ }
+
+ if (common_chars >= 0) {
+ /* multiple match, restore prompt */
+ console_printf("%s", get_prompt());
+ console_printf("%s", line);
+ } else {
+ common_chars = strlen(first_match);
+ space = 1;
+ }
+
+ /* complete common part */
+ for (i = module_len; i < common_chars; i++) {
+ console_printf("%c", first_match[i]);
+ line[len++] = first_match[i];
+ }
+
+ /* for convenience add space after command */
+ if (space) {
+ console_printf(" ");
+ line[len] = ' ';
+ }
+
+ return common_chars - module_len + space;
+}
+
+static int
+complete_select(char *line, int len, char *cur, int tok_len)
+{
+ int null_terminated = 0;
+ cur += tok_len + 1;
+ tok_len = get_token(&cur, &null_terminated);
+ if (tok_len == 0) {
+ if (default_module != -1) {
+ return 0;
+ }
+ console_printf("\n");
+ print_modules();
+ console_printf("%s", get_prompt());
+ console_printf("%s", line);
+ return 0;
+ }
+
+ if (null_terminated) {
+ if (default_module == -1) {
+ return complete_module(line, len, cur, tok_len);
+ }
+ }
+ return 0;
+}
+
+static uint8_t
+completion(char *line, uint8_t len)
+{
+ char *cur;
+ int tok_len;
+ int module, command;
+ int null_terminated = 0;
+
+ /*
+ * line to completion is not ended by '\0' as the line that gets from
+ * os_eventq_get function
+ */
+ line[len] = '\0';
+
+ cur = line;
+ tok_len = get_token(&cur, &null_terminated);
+
+ /* empty token - print options */
+ if (tok_len == 0) {
+ console_printf("\n");
+ if (default_module == -1) {
+ print_modules();
+ } else {
+ print_module_commands(default_module);
+ }
+ console_printf("%s", get_prompt());
+ console_printf("%s", line);
+ return 0;
+ }
+
+ /* token can be completed */
+ if (null_terminated) {
+ if (default_module == -1) {
+ return complete_module(line, len, cur, tok_len);
+ }
+ return complete_command(line, len, cur, tok_len, default_module);
+ }
+
+ if (strncmp("select", cur, tok_len) == 0) {
+ return complete_select(line, len, cur, tok_len);
+ }
+
+ if (default_module != -1) {
+ module = default_module;
+ } else {
+ module = get_destination_module(cur, tok_len);
+
+ if (module == -1) {
+ return 0;
+ }
+
+ cur += tok_len + 1;
+ tok_len = get_token(&cur, &null_terminated);
+
+ if (tok_len == 0) {
+ console_printf("\n");
+ print_module_commands(module);
+ console_printf("%s", get_prompt());
+ console_printf("%s", line);
+ return 0;
+ }
+
+ if (null_terminated) {
+ return complete_command(line, len, cur, tok_len, module);
+ }
+ }
+
+
+
+ command = get_command_from_module(cur, tok_len, module);
+ if (command == -1) {
+ return 0;
+ }
+
+ cur += tok_len;
+ tok_len = get_last_token(&cur);
+ if (tok_len == 0) {
+ console_printf("\n");
+ print_command_params(module, command);
+ console_printf("%s", get_prompt());
+ console_printf("%s", line);
+ return 0;
+ }
+ return complete_param(line, len, cur, tok_len, module, command);
+}
+#endif /* MYNEWT_VAL(SHELL_COMPLETION) */
+
void
shell_register_app_cmd_handler(shell_cmd_func_t handler)
{
@@ -492,6 +893,10 @@ shell_init(void)
prompt = SHELL_PROMPT;
console_set_queues(&avail_queue, os_eventq_dflt_get());
+#if MYNEWT_VAL(SHELL_COMPLETION)
+ console_set_completion_cb(completion);
+#endif
+
#if MYNEWT_VAL(SHELL_OS_MODULE)
shell_os_register(shell_register);
#endif
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/038dc7f4/sys/shell/syscfg.yml
----------------------------------------------------------------------
diff --git a/sys/shell/syscfg.yml b/sys/shell/syscfg.yml
index b3092f5..e4d78f8 100644
--- a/sys/shell/syscfg.yml
+++ b/sys/shell/syscfg.yml
@@ -41,6 +41,9 @@ syscfg.defs:
SHELL_MAX_COMPAT_COMMANDS:
description: 'Max number of compatibility commands'
value: 10
+ SHELL_COMPLETION:
+ description: 'Include completion functionality'
+ value: 1
SHELL_OS_MODULE:
description: 'Include shell os module'