[njs] Shell: simplified input completion handler.
Dmitry Volyntsev
xeioex at nginx.com
Wed May 10 02:00:04 UTC 2023
details: https://hg.nginx.org/njs/rev/d610d744bbd2
branches:
changeset: 2110:d610d744bbd2
user: Dmitry Volyntsev <xeioex at 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:
More information about the nginx-devel
mailing list