details: https://hg.nginx.org/njs/rev/d610d744bbd2 branches: changeset: 2110:d610d744bbd2 user: Dmitry Volyntsev <xei...@nginx.com> date: Mon May 08 22:03:32 2023 -0700 description: Shell: simplified input completion handler.
Previously, the completion logic was split between njs_vm_completion() and njs_completion_generator() in shell. Now the completion part is done in njs_vm_completion(), as a result njs_completion_generator() is simplified. diffstat: src/njs_builtin.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++-- src/njs_shell.c | 88 +++---------------------------------------- 2 files changed, 110 insertions(+), 86 deletions(-) diffs (312 lines): diff -r 2467a70fd45a -r d610d744bbd2 src/njs_builtin.c --- a/src/njs_builtin.c Mon May 08 16:40:50 2023 -0700 +++ b/src/njs_builtin.c Mon May 08 22:03:32 2023 -0700 @@ -27,7 +27,10 @@ static njs_int_t njs_global_this_prop_ha njs_value_t *retval); static njs_arr_t *njs_vm_expression_completions(njs_vm_t *vm, njs_str_t *expression); -static njs_arr_t *njs_object_completions(njs_vm_t *vm, njs_value_t *object); +static njs_arr_t *njs_vm_global_var_completions(njs_vm_t *vm, + njs_str_t *expression); +static njs_arr_t *njs_object_completions(njs_vm_t *vm, njs_value_t *object, + njs_str_t *expression); static njs_int_t njs_env_hash_init(njs_vm_t *vm, njs_lvlhsh_t *hash, char **environment); @@ -544,15 +547,76 @@ njs_builtin_completions(njs_vm_t *vm) njs_arr_t * njs_vm_completions(njs_vm_t *vm, njs_str_t *expression) { + u_char *p, *end; + if (expression == NULL) { return njs_builtin_completions(vm); } + p = expression->start; + end = p + expression->length; + + while (p < end && *p != '.') { p++; } + + if (p == end) { + return njs_vm_global_var_completions(vm, expression); + } + return njs_vm_expression_completions(vm, expression); } static njs_arr_t * +njs_vm_global_var_completions(njs_vm_t *vm, njs_str_t *expression) +{ + njs_str_t *completion; + njs_arr_t *array; + njs_rbtree_t *variables; + njs_rbtree_node_t *node; + njs_variable_node_t *vnode; + const njs_lexer_entry_t *lex_entry; + + variables = (vm->global_scope != NULL) ? &vm->global_scope->variables + : NULL; + if (njs_slow_path(variables == NULL)) { + return NULL; + } + + array = njs_arr_create(vm->mem_pool, 8, sizeof(njs_str_t)); + if (njs_slow_path(array == NULL)) { + return NULL; + } + + node = njs_rbtree_min(variables); + + while (njs_rbtree_is_there_successor(variables, node)) { + vnode = (njs_variable_node_t *) node; + + node = njs_rbtree_node_successor(variables, node); + + lex_entry = njs_lexer_entry(vnode->key); + if (lex_entry == NULL) { + continue; + } + + if (lex_entry->name.length >= expression->length + && njs_strncmp(expression->start, lex_entry->name.start, + expression->length) == 0) + { + completion = njs_arr_add(array); + if (njs_slow_path(completion == NULL)) { + return NULL; + } + + *completion = lex_entry->name; + } + } + + return array; +} + + +static njs_arr_t * njs_vm_expression_completions(njs_vm_t *vm, njs_str_t *expression) { u_char *p, *end; @@ -611,6 +675,10 @@ njs_vm_expression_completions(njs_vm_t * ret = njs_lvlhsh_find(njs_object_hash(value), &lhq); if (njs_slow_path(ret != NJS_OK)) { + if (ret == NJS_DECLINED) { + break; + } + return NULL; } @@ -625,20 +693,31 @@ njs_vm_expression_completions(njs_vm_t * value = njs_prop_value(prop); } - return njs_object_completions(vm, value); + return njs_object_completions(vm, value, expression); } static njs_arr_t * -njs_object_completions(njs_vm_t *vm, njs_value_t *object) +njs_object_completions(njs_vm_t *vm, njs_value_t *object, njs_str_t *expression) { + u_char *prefix; double num; + size_t len; njs_arr_t *array; - njs_str_t *completion; + njs_str_t *completion, key; njs_uint_t n; njs_array_t *keys; njs_value_type_t type; + prefix = expression->start + expression->length; + + while (prefix > expression->start && *prefix != '.') { + prefix--; + } + + prefix++; + len = expression->length - (prefix - expression->start); + array = NULL; type = object->type; @@ -657,6 +736,14 @@ njs_object_completions(njs_vm_t *vm, njs } for (n = 0; n < keys->length; n++) { + njs_string_get(&keys->start[n], &key); + + if (len != 0 + && njs_strncmp(key.start, prefix, njs_min(len, key.length)) != 0) + { + continue; + } + num = njs_key_to_index(&keys->start[n]); if (!njs_key_is_integer_index(num, &keys->start[n])) { @@ -667,7 +754,18 @@ njs_object_completions(njs_vm_t *vm, njs goto done; } - njs_string_get(&keys->start[n], completion); + completion->length = (prefix - expression->start) + key.length + 1; + completion->start = njs_mp_alloc(vm->mem_pool, completion->length); + if (completion == NULL) { + njs_arr_destroy(array); + array = NULL; + goto done; + } + + njs_sprintf(completion->start, + completion->start + completion->length, + "%*s%V%Z", prefix - expression->start, + expression->start, &key); } } diff -r 2467a70fd45a -r d610d744bbd2 src/njs_shell.c --- a/src/njs_shell.c Mon May 08 16:40:50 2023 -0700 +++ b/src/njs_shell.c Mon May 08 22:03:32 2023 -0700 @@ -63,8 +63,7 @@ typedef struct { njs_rbtree_node_t *node; enum { - NJS_COMPLETION_VAR = 0, - NJS_COMPLETION_SUFFIX, + NJS_COMPLETION_SUFFIX = 0, NJS_COMPLETION_GLOBAL } phase; } njs_completion_t; @@ -1189,78 +1188,31 @@ njs_editline_init(void) static char * njs_completion_generator(const char *text, int state) { - char *completion; - size_t len; - njs_str_t expression, *suffix; - njs_vm_t *vm; - const char *p; - njs_rbtree_t *variables; - njs_completion_t *cmpl; - njs_variable_node_t *var_node; - const njs_lexer_entry_t *lex_entry; + njs_str_t expression, *suffix; + njs_vm_t *vm; + njs_completion_t *cmpl; vm = njs_console.vm; cmpl = &njs_console.completion; if (state == 0) { - cmpl->phase = 0; + cmpl->phase = NJS_COMPLETION_SUFFIX; cmpl->index = 0; cmpl->length = njs_strlen(text); cmpl->suffix_completions = NULL; - - if (vm->global_scope != NULL) { - cmpl->node = njs_rbtree_min(&vm->global_scope->variables); - } } next: switch (cmpl->phase) { - case NJS_COMPLETION_VAR: - variables = (vm->global_scope != NULL) ? &vm->global_scope->variables - : NULL; - - if (variables == NULL) { - njs_next_phase(cmpl); - } - - while (njs_rbtree_is_there_successor(variables, cmpl->node)) { - var_node = (njs_variable_node_t *) cmpl->node; - - lex_entry = njs_lexer_entry(var_node->key); - if (lex_entry == NULL) { - break; - } - - cmpl->node = njs_rbtree_node_successor(variables, cmpl->node); - - if (lex_entry->name.length >= cmpl->length - && njs_strncmp(text, lex_entry->name.start, cmpl->length) == 0) - { - return njs_editline(&lex_entry->name); - } - - } - - njs_next_phase(cmpl); - case NJS_COMPLETION_SUFFIX: if (cmpl->length == 0) { njs_next_phase(cmpl); } if (cmpl->suffix_completions == NULL) { - /* Getting the longest prefix before a '.' */ - - p = &text[cmpl->length - 1]; - while (p > text && *p != '.') { p--; } - - if (*p != '.') { - njs_next_phase(cmpl); - } - expression.start = (u_char *) text; - expression.length = p - text; + expression.length = cmpl->length; cmpl->suffix_completions = njs_vm_completions(vm, &expression); if (cmpl->suffix_completions == NULL) { @@ -1268,18 +1220,6 @@ next: } } - /* Getting the right-most suffix after a '.' */ - - len = 0; - p = &text[cmpl->length - 1]; - - while (p > text && *p != '.') { - p--; - len++; - } - - p++; - for ( ;; ) { if (cmpl->index >= cmpl->suffix_completions->items) { njs_next_phase(cmpl); @@ -1287,21 +1227,7 @@ next: suffix = njs_completion(cmpl->suffix_completions, cmpl->index++); - if (len != 0 && njs_strncmp(suffix->start, p, - njs_min(len, suffix->length)) != 0) - { - continue; - } - - len = suffix->length + (p - text) + 1; - completion = malloc(len); - if (completion == NULL) { - return NULL; - } - - njs_sprintf((u_char *) completion, (u_char *) completion + len, - "%*s%V%Z", p - text, text, suffix); - return completion; + return njs_editline(suffix); } case NJS_COMPLETION_GLOBAL: _______________________________________________ nginx-devel mailing list nginx-devel@nginx.org https://mailman.nginx.org/mailman/listinfo/nginx-devel