/* Executes keys from the start of key sequence or at some offset in it. * Returns error code. */ static int dispatch_keys(const wchar_t keys[], keys_info_t *keys_info, int no_remap, int prev_count) { key_info_t key_info; int result; keys = get_reg(keys, &key_info.reg); if(keys == NULL) { return KEYS_WAIT; } if(key_info.reg == L'\x1b' || key_info.reg == L'\x03') { return 0; } keys = get_count(keys, &key_info.count); key_info.count = combine_counts(key_info.count, prev_count); key_info.multi = L'\0'; if(!no_remap) { key_chunk_t *const root = keys_info->selector ? &selectors_root[vle_mode_get()] : &user_cmds_root[vle_mode_get()]; result = dispatch_keys_at_root(keys, keys_info, root, key_info, no_remap); } else { result = KEYS_UNKNOWN; } if(result == KEYS_UNKNOWN && !keys_info->selector) { result = dispatch_keys_at_root(keys, keys_info, &builtin_cmds_root[vle_mode_get()], key_info, no_remap); } return result; }
/* Fills *key_info advancing input if necessary. Returns zero on success, * otherwise non-zero is returned and *result is set. */ static int fill_key_info(const wchar_t **keys, key_info_t *key_info, int prev_count, int *result) { *keys = get_reg(*keys, &key_info->reg); if(*keys == NULL) { *result = KEYS_WAIT; return 1; } if(key_info->reg == L'\x1b' || key_info->reg == L'\x03') { *result = 0; return 1; } *keys = get_count(*keys, &key_info->count); key_info->count = combine_counts(key_info->count, prev_count); key_info->multi = L'\0'; return 0; }
/* Dispatches keys passed in using a tree of shortcuts registered in the root. * Returns error code. */ static int dispatch_keys_at_root(const wchar_t keys[], keys_info_t *keys_info, key_chunk_t *root, key_info_t key_info, int no_remap) { key_chunk_t *curr; const wchar_t *keys_start = keys; int has_duplicate; int result; /* The loop finds longest match of the input (keys) amoung registered * shortcuts. */ curr = root; while(*keys != L'\0') { key_chunk_t *p; int number_in_the_middle = 0; p = curr->child; while(p != NULL && p->key < *keys) { if(p->conf.type == BUILTIN_NIM_KEYS) { number_in_the_middle = 1; } p = p->next; } if(p == NULL || p->key != *keys) { if(curr == root) return KEYS_UNKNOWN; while(p != NULL) { if(p->conf.type == BUILTIN_NIM_KEYS) { number_in_the_middle = 1; } p = p->next; } if(curr->conf.followed != FOLLOWED_BY_NONE && (!number_in_the_middle || !is_at_count(keys))) { break; } if(number_in_the_middle) { int count; const wchar_t *new_keys = get_count(keys, &count); if(new_keys != keys) { key_info.count = combine_counts(key_info.count, count); keys = new_keys; continue; } } if(curr->conf.type == BUILTIN_WAIT_POINT) { return KEYS_UNKNOWN; } has_duplicate = root == &user_cmds_root[vle_mode_get()] && contains_chain(&builtin_cmds_root[vle_mode_get()], keys_start, keys); result = execute_next_keys(curr, curr->conf.type == USER_CMD ? keys : L"", &key_info, keys_info, has_duplicate, no_remap); if(curr->conf.type == USER_CMD) return result; if(IS_KEYS_RET_CODE(result)) { if(result == KEYS_WAIT_SHORT) return KEYS_UNKNOWN; return result; } inc_counter(keys_info, keys - keys_start); return execute_keys_general(keys, 0, keys_info->mapped, no_remap); } keys++; curr = p; } if(*keys == '\0' && curr->conf.type != BUILTIN_WAIT_POINT && curr->children_count > 0 && curr->conf.data.handler != NULL && !keys_info->after_wait) { return KEYS_WAIT_SHORT; } has_duplicate = root == &user_cmds_root[vle_mode_get()] && contains_chain(&builtin_cmds_root[vle_mode_get()], keys_start, keys); result = execute_next_keys(curr, keys, &key_info, keys_info, has_duplicate, no_remap); if(!IS_KEYS_RET_CODE(result)) { inc_counter(keys_info, keys - keys_start); } else if(*keys == '\0' && result == KEYS_UNKNOWN && curr->children_count > 0) { return keys_info->after_wait ? KEYS_UNKNOWN : KEYS_WAIT_SHORT; } return result; }