/* 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; if(fill_key_info(&keys, &key_info, prev_count, &result) != 0) { return result; } result = KEYS_UNKNOWN; if(!no_remap) { result = dispatch_keys_at_root(keys, keys_info, &user_cmds_root[vle_mode_get()], key_info, no_remap); } if(result == KEYS_UNKNOWN) { result = dispatch_keys_at_root(keys, keys_info, &builtin_cmds_root[vle_mode_get()], key_info, no_remap); } return result; }
void vle_keys_suggest(const wchar_t keys[], vle_keys_list_cb cb, int custom_only, int fold_subkeys) { keys_suggest(&user_cmds_root[vle_mode_get()], keys, L"key: ", cb, custom_only, fold_subkeys); keys_suggest(&builtin_cmds_root[vle_mode_get()], keys, L"key: ", cb, custom_only, fold_subkeys); }
/* Updates hardware cursor to be on currently active area of the interface, * which depends mainly on current mode.. */ static void update_hardware_cursor(void) { if(ui_sb_multiline()) { checked_wmove(status_bar, 0, 0); ui_refresh_win(status_bar); return; } switch(vle_mode_get()) { case MENU_MODE: case FILE_INFO_MODE: case MORE_MODE: ui_refresh_win(menu_win); break; case CHANGE_MODE: case ATTR_MODE: ui_refresh_win(change_win); break; case MSG_MODE: ui_refresh_win(error_win); break; case VIEW_MODE: ui_refresh_win(curr_view->win); break; case SORT_MODE: ui_refresh_win(sort_win); break; case NORMAL_MODE: case VISUAL_MODE: if(should_check_views_for_changes()) { ui_refresh_win(curr_view->win); } break; } }
void clear_input_bar(void) { if(uses_input_bar[vle_mode_get()] && !vle_mode_is(VISUAL_MODE)) { clear_num_window(); } }
/* 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; }
/* Checks keys for a count. Returns non-zero if there is count in the current * position. */ static int is_at_count(const wchar_t keys[]) { if((mode_flags[vle_mode_get()] & MF_USES_COUNT) != 0) { if(keys[0] != L'0' && iswdigit(keys[0])) { return 1; } } return 0; }
void modupd_input_bar(wchar_t *str) { if(vle_mode_is(VISUAL_MODE)) { clear_input_bar(); } if(uses_input_bar[vle_mode_get()]) { update_input_bar(str); } }
static int execute_keys_general(const wchar_t keys[], int timed_out, int mapped, int no_remap) { int result; keys_info_t keys_info; if(keys[0] == L'\0') { return KEYS_UNKNOWN; } init_keys_info(&keys_info, mapped); keys_info.after_wait = timed_out; result = dispatch_keys(keys, &keys_info, no_remap, NO_COUNT_GIVEN); if(result == KEYS_UNKNOWN && def_handlers[vle_mode_get()] != NULL) { result = def_handlers[vle_mode_get()](keys[0]); execute_keys_general(keys + 1, 0, mapped, no_remap); } return result; }
/* Enters the mode, which won't be left until one of expected results specified * by the mask is picked by the user. */ static void enter(int result_mask) { accept_mask = result_mask; prev_use_input_bar = curr_stats.use_input_bar; curr_stats.use_input_bar = 0; prev_mode = vle_mode_get(); vle_mode_set(MSG_MODE, VMT_SECONDARY); quit = 0; event_loop(&quit); }
/* Handles the rest of the keys after first one has been determined (in curr). * These can be: <nothing> (empty line), selector, multikey argument. Returns * error code. */ static int execute_next_keys(key_chunk_t *curr, const wchar_t keys[], key_info_t *key_info, keys_info_t *keys_info, int has_duplicate, int no_remap) { const key_conf_t *const conf = &curr->conf; if(*keys == L'\0') { int wait_point = (conf->type == BUILTIN_WAIT_POINT); wait_point = wait_point || (conf->type == USER_CMD && conf->followed != FOLLOWED_BY_NONE); if(wait_point) { const int with_input = (mode_flags[vle_mode_get()] & MF_USES_INPUT); if(!keys_info->after_wait) { return (with_input || has_duplicate) ? KEYS_WAIT_SHORT : KEYS_WAIT; } } else if(conf->data.handler == NULL || conf->followed != FOLLOWED_BY_NONE) { return KEYS_UNKNOWN; } } else if(conf->type != USER_CMD) { int result; if(conf->followed == FOLLOWED_BY_MULTIKEY) { key_info->multi = keys[0]; return dispatch_key(*key_info, keys_info, curr, keys + 1); } keys_info->selector = 1; result = dispatch_keys(keys, keys_info, no_remap, key_info->count); keys_info->selector = 0; if(IS_KEYS_RET_CODE(result)) { return result; } /* We used this count in selector, so don't pass it to command. */ key_info->count = NO_COUNT_GIVEN; } return dispatch_key(*key_info, keys_info, curr, keys); }
static const wchar_t * get_reg(const wchar_t *keys, int *reg) { *reg = NO_REG_GIVEN; if((mode_flags[vle_mode_get()] & MF_USES_REGS) == 0) { return keys; } if(keys[0] == L'"') { if(keys[1] == L'\0') { return NULL; } *reg = keys[1]; keys += 2; } return keys; }
/* Handles the rest of the keys after first one has been determined (in curr). * These can be: <nothing> (empty line), selector, multikey argument. Returns * error code. */ static int execute_next_keys(key_chunk_t *curr, const wchar_t keys[], key_info_t *key_info, keys_info_t *keys_info, int has_duplicate, int no_remap) { const key_conf_t *const conf = &curr->conf; if(*keys == L'\0') { int wait_point = (curr->type == BUILTIN_WAIT_POINT); wait_point = wait_point || (curr->type == USER_CMD && conf->followed != FOLLOWED_BY_NONE); if(wait_point) { const int with_input = (mode_flags[vle_mode_get()] & MF_USES_INPUT); if(!keys_info->after_wait) { return (with_input || has_duplicate) ? KEYS_WAIT_SHORT : KEYS_WAIT; } } else if(conf->data.handler == NULL || conf->followed != FOLLOWED_BY_NONE) { return KEYS_UNKNOWN; } } else if(curr->type != USER_CMD) { if(conf->followed == FOLLOWED_BY_MULTIKEY) { key_info->multi = keys[0]; return dispatch_key(*key_info, keys_info, curr, keys + 1); } keys_info->selector = 1; return dispatch_selector(keys, keys_info, *key_info, curr, no_remap); } return dispatch_key(*key_info, keys_info, curr, keys); }
/* Gets default handler of active mode. Returns the handler, which is NULL when * not set for active mode. */ static default_handler def_handler(void) { return def_handlers[vle_mode_get()]; }
/* 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; }
/* Dispatches keys passed in as a selector followed by arbitrary other keys. * Returns error code. */ static int dispatch_selector(const wchar_t keys[], keys_info_t *keys_info, key_info_t master_key_info, key_chunk_t *master_curr, int no_remap) { const wchar_t *keys_start = keys; key_chunk_t *curr = &selectors_root[vle_mode_get()]; key_info_t key_info; int result; if(fill_key_info(&keys, &key_info, master_key_info.count, &result) != 0) { return result; } /* The loop finds longest match of the input (keys) among registered * shortcuts. */ while(*keys != L'\0') { key_chunk_t *p; for(p = curr->child; p != NULL && p->key < *keys; p = p->next) { /* Advance. */ } if(p == NULL || p->key != *keys) { break; } ++keys; curr = p; } /* Handle ambiguous selector. */ if(*keys == '\0' && curr->type != BUILTIN_WAIT_POINT && curr->children_count > 0 && curr->conf.data.handler != NULL && !keys_info->after_wait) { return KEYS_WAIT_SHORT; } /* Execute the selector. */ if(curr->conf.followed == FOLLOWED_BY_MULTIKEY && keys[0] != L'\0') { const wchar_t mk[] = { keys[0], L'\0' }; result = execute_next_keys(curr, mk, &key_info, keys_info, 0, no_remap); ++keys; } else { result = keys[0] == L'\0' ? execute_next_keys(curr, L"", &key_info, keys_info, 0, no_remap) : dispatch_key(key_info, keys_info, curr, L""); } if(IS_KEYS_RET_CODE(result)) { return result; } /* We used this count in selector, so don't pass it to command. */ master_key_info.count = NO_COUNT_GIVEN; /* Execute command that requested the selector. */ result = execute_mapping_handler(&master_curr->conf, master_key_info, keys_info); if(IS_KEYS_RET_CODE(result)) { return result; } inc_counter(keys_info, keys - keys_start); /* execute_keys_general() treats empty input as an error. */ if(keys[0] == L'\0') { return 0; } /* Process the rest of the line. */ return execute_keys_general(keys, keys_info->after_wait, 0, no_remap); }
/* Looks up possible continuations of keys for the given root and calls cb on * them. */ static void keys_suggest(const key_chunk_t *root, const wchar_t keys[], const wchar_t prefix[], vle_keys_list_cb cb, int custom_only, int fold_subkeys) { const key_chunk_t *curr = root; while(*keys != L'\0') { const key_chunk_t *p; int number_in_the_middle = 0; /* Look up current key among children of current node (might be root), while * inspecting NIM as well. */ for(p = curr->child; p != NULL && p->key < *keys; p = p->next) { if(p->type == BUILTIN_NIM_KEYS) { number_in_the_middle = 1; } } /* Go to the next character if a match found. */ if(p != NULL && p->key == *keys) { ++keys; curr = p; continue; } /* No match for the first character is fatal for the lookup. */ if(curr == root) { return; } /* Need to inspect all children for NIM. */ for(; p != NULL && !number_in_the_middle; p = p->next) { if(p->type == BUILTIN_NIM_KEYS) { number_in_the_middle = 1; } } /* Give up if this isn't one of cases where next character is not presented * in the tree by design. */ if(curr->conf.followed != FOLLOWED_BY_NONE && (!number_in_the_middle || !is_at_count(keys))) { break; } /* Skip over number in the middle, if any. */ if(number_in_the_middle) { int count; const wchar_t *new_keys = get_count(keys, &count); if(new_keys != keys) { keys = new_keys; continue; } } break; } if(!custom_only && *keys == L'\0') { suggest_children(curr, prefix, cb, fold_subkeys); } if(curr->type == BUILTIN_WAIT_POINT) { if(curr->conf.followed == FOLLOWED_BY_SELECTOR) { /* Suggest selectors. */ keys_suggest(&selectors_root[vle_mode_get()], keys, L"sel: ", cb, custom_only, fold_subkeys); } else if(curr->conf.followed == FOLLOWED_BY_MULTIKEY) { /* Invoke optional external function to provide suggestions. */ if(curr->conf.suggest != NULL) { curr->conf.suggest(cb); } } } }