diff options
author | Bram Moolenaar <Bram@vim.org> | 2020-09-04 15:37:31 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2020-09-04 15:37:31 +0200 |
commit | eadee486c70946ad0e1746d77898d6f4f4acc817 (patch) | |
tree | d36a72738e256191c2201dd015940cbcc2f13321 /src/cmdexpand.c | |
parent | fe6dce873954a216eedb686bd5006710ffff4b89 (diff) |
patch 8.2.1587: loop for handling keys for the command line is too longv8.2.1587
Problem: Loop for handling keys for the command line is too long.
Solution: Move wild menu handling to separate functions. (Yegappan
Lakshmanan, closes #6856)
Diffstat (limited to 'src/cmdexpand.c')
-rw-r--r-- | src/cmdexpand.c | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/src/cmdexpand.c b/src/cmdexpand.c index fe82ab7d4a..79fb006b24 100644 --- a/src/cmdexpand.c +++ b/src/cmdexpand.c @@ -2614,6 +2614,255 @@ globpath( vim_free(buf); } +#ifdef FEAT_WILDMENU + +/* + * Translate some keys pressed when 'wildmenu' is used. + */ + int +wildmenu_translate_key( + cmdline_info_T *cclp, + int key, + expand_T *xp, + int did_wild_list) +{ + int c = key; + + if (did_wild_list && p_wmnu) + { + if (c == K_LEFT) + c = Ctrl_P; + else if (c == K_RIGHT) + c = Ctrl_N; + } + // Hitting CR after "emenu Name.": complete submenu + if (xp->xp_context == EXPAND_MENUNAMES && p_wmnu + && cclp->cmdpos > 1 + && cclp->cmdbuff[cclp->cmdpos - 1] == '.' + && cclp->cmdbuff[cclp->cmdpos - 2] != '\\' + && (c == '\n' || c == '\r' || c == K_KENTER)) + c = K_DOWN; + + return c; +} + +/* + * Delete characters on the command line, from "from" to the current + * position. + */ + static void +cmdline_del(cmdline_info_T *cclp, int from) +{ + mch_memmove(cclp->cmdbuff + from, cclp->cmdbuff + cclp->cmdpos, + (size_t)(cclp->cmdlen - cclp->cmdpos + 1)); + cclp->cmdlen -= cclp->cmdpos - from; + cclp->cmdpos = from; +} + +/* + * Handle a key pressed when wild menu is displayed + */ + int +wildmenu_process_key(cmdline_info_T *cclp, int key, expand_T *xp) +{ + int c = key; + int i; + int j; + + if (!p_wmnu) + return c; + + // Special translations for 'wildmenu' + if (xp->xp_context == EXPAND_MENUNAMES) + { + // Hitting <Down> after "emenu Name.": complete submenu + if (c == K_DOWN && cclp->cmdpos > 0 + && cclp->cmdbuff[cclp->cmdpos - 1] == '.') + c = p_wc; + else if (c == K_UP) + { + // Hitting <Up>: Remove one submenu name in front of the + // cursor + int found = FALSE; + + j = (int)(xp->xp_pattern - cclp->cmdbuff); + i = 0; + while (--j > 0) + { + // check for start of menu name + if (cclp->cmdbuff[j] == ' ' + && cclp->cmdbuff[j - 1] != '\\') + { + i = j + 1; + break; + } + // check for start of submenu name + if (cclp->cmdbuff[j] == '.' + && cclp->cmdbuff[j - 1] != '\\') + { + if (found) + { + i = j + 1; + break; + } + else + found = TRUE; + } + } + if (i > 0) + cmdline_del(cclp, i); + c = p_wc; + xp->xp_context = EXPAND_NOTHING; + } + } + if ((xp->xp_context == EXPAND_FILES + || xp->xp_context == EXPAND_DIRECTORIES + || xp->xp_context == EXPAND_SHELLCMD)) + { + char_u upseg[5]; + + upseg[0] = PATHSEP; + upseg[1] = '.'; + upseg[2] = '.'; + upseg[3] = PATHSEP; + upseg[4] = NUL; + + if (c == K_DOWN + && cclp->cmdpos > 0 + && cclp->cmdbuff[cclp->cmdpos - 1] == PATHSEP + && (cclp->cmdpos < 3 + || cclp->cmdbuff[cclp->cmdpos - 2] != '.' + || cclp->cmdbuff[cclp->cmdpos - 3] != '.')) + { + // go down a directory + c = p_wc; + } + else if (STRNCMP(xp->xp_pattern, upseg + 1, 3) == 0 && c == K_DOWN) + { + // If in a direct ancestor, strip off one ../ to go down + int found = FALSE; + + j = cclp->cmdpos; + i = (int)(xp->xp_pattern - cclp->cmdbuff); + while (--j > i) + { + if (has_mbyte) + j -= (*mb_head_off)(cclp->cmdbuff, cclp->cmdbuff + j); + if (vim_ispathsep(cclp->cmdbuff[j])) + { + found = TRUE; + break; + } + } + if (found + && cclp->cmdbuff[j - 1] == '.' + && cclp->cmdbuff[j - 2] == '.' + && (vim_ispathsep(cclp->cmdbuff[j - 3]) || j == i + 2)) + { + cmdline_del(cclp, j - 2); + c = p_wc; + } + } + else if (c == K_UP) + { + // go up a directory + int found = FALSE; + + j = cclp->cmdpos - 1; + i = (int)(xp->xp_pattern - cclp->cmdbuff); + while (--j > i) + { + if (has_mbyte) + j -= (*mb_head_off)(cclp->cmdbuff, cclp->cmdbuff + j); + if (vim_ispathsep(cclp->cmdbuff[j]) +# ifdef BACKSLASH_IN_FILENAME + && vim_strchr((char_u *)" *?[{`$%#", + cclp->cmdbuff[j + 1]) == NULL +# endif + ) + { + if (found) + { + i = j + 1; + break; + } + else + found = TRUE; + } + } + + if (!found) + j = i; + else if (STRNCMP(cclp->cmdbuff + j, upseg, 4) == 0) + j += 4; + else if (STRNCMP(cclp->cmdbuff + j, upseg + 1, 3) == 0 + && j == i) + j += 3; + else + j = 0; + if (j > 0) + { + // TODO this is only for DOS/UNIX systems - need to put in + // machine-specific stuff here and in upseg init + cmdline_del(cclp, j); + put_on_cmdline(upseg + 1, 3, FALSE); + } + else if (cclp->cmdpos > i) + cmdline_del(cclp, i); + + // Now complete in the new directory. Set KeyTyped in case the + // Up key came from a mapping. + c = p_wc; + KeyTyped = TRUE; + } + } + + return c; +} + +/* + * Free expanded names when finished walking through the matches + */ + void +wildmenu_cleanup(cmdline_info_T *cclp) +{ + int skt = KeyTyped; + int old_RedrawingDisabled = RedrawingDisabled; + + if (!p_wmnu || wild_menu_showing == 0) + return; + + if (cclp->input_fn) + RedrawingDisabled = 0; + + if (wild_menu_showing == WM_SCROLLED) + { + // Entered command line, move it up + cmdline_row--; + redrawcmd(); + } + else if (save_p_ls != -1) + { + // restore 'laststatus' and 'winminheight' + p_ls = save_p_ls; + p_wmh = save_p_wmh; + last_status(FALSE); + update_screen(VALID); // redraw the screen NOW + redrawcmd(); + save_p_ls = -1; + } + else + { + win_redraw_last_status(topframe); + redraw_statuslines(); + } + KeyTyped = skt; + wild_menu_showing = 0; + if (cclp->input_fn) + RedrawingDisabled = old_RedrawingDisabled; +} +#endif + #if defined(FEAT_EVAL) || defined(PROTO) /* * "getcompletion()" function |