# HG changeset patch # User Bram Moolenaar # Date 1599227103 -7200 # Node ID eb878f85967ef40a9b8854b4ea237002d6248fa9 # Parent 923f618adb59f56211691ee137c799800784620e patch 8.2.1587: loop for handling keys for the command line is too long Commit: https://github.com/vim/vim/commit/eadee486c70946ad0e1746d77898d6f4f4acc817 Author: Bram Moolenaar Date: Fri Sep 4 15:37:31 2020 +0200 patch 8.2.1587: loop for handling keys for the command line is too long Problem: Loop for handling keys for the command line is too long. Solution: Move wild menu handling to separate functions. (Yegappan Lakshmanan, closes #6856) diff --git a/src/cmdexpand.c b/src/cmdexpand.c --- 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 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 : 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 diff --git a/src/ex_getln.c b/src/ex_getln.c --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -44,9 +44,6 @@ static void draw_cmdline(int start, int static void save_cmdline(cmdline_info_T *ccp); static void restore_cmdline(cmdline_info_T *ccp); static int cmdline_paste(int regname, int literally, int remcr); -#ifdef FEAT_WILDMENU -static void cmdline_del(int from); -#endif static void redrawcmdprompt(void); static int ccheck_abbr(int); @@ -1064,21 +1061,7 @@ getcmdline_int( c = Ctrl_P; #ifdef FEAT_WILDMENU - // Special translations for 'wildmenu' - 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 (xpc.xp_context == EXPAND_MENUNAMES && p_wmnu - && ccline.cmdpos > 1 - && ccline.cmdbuff[ccline.cmdpos - 1] == '.' - && ccline.cmdbuff[ccline.cmdpos - 2] != '\\' - && (c == '\n' || c == '\r' || c == K_KENTER)) - c = K_DOWN; + c = wildmenu_translate_key(&ccline, c, &xpc, did_wild_list); #endif // free expanded names when finished walking through matches @@ -1095,190 +1078,13 @@ getcmdline_int( xpc.xp_context = EXPAND_NOTHING; wim_index = 0; #ifdef FEAT_WILDMENU - if (p_wmnu && wild_menu_showing != 0) - { - int skt = KeyTyped; - int old_RedrawingDisabled = RedrawingDisabled; - - if (ccline.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 (ccline.input_fn) - RedrawingDisabled = old_RedrawingDisabled; - } + wildmenu_cleanup(&ccline); #endif } #ifdef FEAT_WILDMENU - // Special translations for 'wildmenu' - if (xpc.xp_context == EXPAND_MENUNAMES && p_wmnu) - { - // Hitting after "emenu Name.": complete submenu - if (c == K_DOWN && ccline.cmdpos > 0 - && ccline.cmdbuff[ccline.cmdpos - 1] == '.') - c = p_wc; - else if (c == K_UP) - { - // Hitting : Remove one submenu name in front of the - // cursor - int found = FALSE; - - j = (int)(xpc.xp_pattern - ccline.cmdbuff); - i = 0; - while (--j > 0) - { - // check for start of menu name - if (ccline.cmdbuff[j] == ' ' - && ccline.cmdbuff[j - 1] != '\\') - { - i = j + 1; - break; - } - // check for start of submenu name - if (ccline.cmdbuff[j] == '.' - && ccline.cmdbuff[j - 1] != '\\') - { - if (found) - { - i = j + 1; - break; - } - else - found = TRUE; - } - } - if (i > 0) - cmdline_del(i); - c = p_wc; - xpc.xp_context = EXPAND_NOTHING; - } - } - if ((xpc.xp_context == EXPAND_FILES - || xpc.xp_context == EXPAND_DIRECTORIES - || xpc.xp_context == EXPAND_SHELLCMD) && p_wmnu) - { - char_u upseg[5]; - - upseg[0] = PATHSEP; - upseg[1] = '.'; - upseg[2] = '.'; - upseg[3] = PATHSEP; - upseg[4] = NUL; - - if (c == K_DOWN - && ccline.cmdpos > 0 - && ccline.cmdbuff[ccline.cmdpos - 1] == PATHSEP - && (ccline.cmdpos < 3 - || ccline.cmdbuff[ccline.cmdpos - 2] != '.' - || ccline.cmdbuff[ccline.cmdpos - 3] != '.')) - { - // go down a directory - c = p_wc; - } - else if (STRNCMP(xpc.xp_pattern, upseg + 1, 3) == 0 && c == K_DOWN) - { - // If in a direct ancestor, strip off one ../ to go down - int found = FALSE; - - j = ccline.cmdpos; - i = (int)(xpc.xp_pattern - ccline.cmdbuff); - while (--j > i) - { - if (has_mbyte) - j -= (*mb_head_off)(ccline.cmdbuff, ccline.cmdbuff + j); - if (vim_ispathsep(ccline.cmdbuff[j])) - { - found = TRUE; - break; - } - } - if (found - && ccline.cmdbuff[j - 1] == '.' - && ccline.cmdbuff[j - 2] == '.' - && (vim_ispathsep(ccline.cmdbuff[j - 3]) || j == i + 2)) - { - cmdline_del(j - 2); - c = p_wc; - } - } - else if (c == K_UP) - { - // go up a directory - int found = FALSE; - - j = ccline.cmdpos - 1; - i = (int)(xpc.xp_pattern - ccline.cmdbuff); - while (--j > i) - { - if (has_mbyte) - j -= (*mb_head_off)(ccline.cmdbuff, ccline.cmdbuff + j); - if (vim_ispathsep(ccline.cmdbuff[j]) -# ifdef BACKSLASH_IN_FILENAME - && vim_strchr((char_u *)" *?[{`$%#", - ccline.cmdbuff[j + 1]) == NULL -# endif - ) - { - if (found) - { - i = j + 1; - break; - } - else - found = TRUE; - } - } - - if (!found) - j = i; - else if (STRNCMP(ccline.cmdbuff + j, upseg, 4) == 0) - j += 4; - else if (STRNCMP(ccline.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(j); - put_on_cmdline(upseg + 1, 3, FALSE); - } - else if (ccline.cmdpos > i) - cmdline_del(i); - - // Now complete in the new directory. Set KeyTyped in case the - // Up key came from a mapping. - c = p_wc; - KeyTyped = TRUE; - } - } - -#endif // FEAT_WILDMENU + c = wildmenu_process_key(&ccline, c, &xpc); +#endif // CTRL-\ CTRL-N goes to Normal mode, CTRL-\ CTRL-G goes to Insert // mode when 'insertmode' is set, CTRL-\ e prompts for an expression. @@ -3660,21 +3466,6 @@ cmdline_paste_str(char_u *s, int literal } } -#ifdef FEAT_WILDMENU -/* - * Delete characters on the command line, from "from" to the current - * position. - */ - static void -cmdline_del(int from) -{ - mch_memmove(ccline.cmdbuff + from, ccline.cmdbuff + ccline.cmdpos, - (size_t)(ccline.cmdlen - ccline.cmdpos + 1)); - ccline.cmdlen -= ccline.cmdpos - from; - ccline.cmdpos = from; -} -#endif - /* * This function is called when the screen size changes and with incremental * search and in other situations where the command line may have been diff --git a/src/proto/cmdexpand.pro b/src/proto/cmdexpand.pro --- a/src/proto/cmdexpand.pro +++ b/src/proto/cmdexpand.pro @@ -9,5 +9,8 @@ char_u *addstar(char_u *fname, int len, void set_cmd_context(expand_T *xp, char_u *str, int len, int col, int use_ccline); int expand_cmdline(expand_T *xp, char_u *str, int col, int *matchcount, char_u ***matches); void globpath(char_u *path, char_u *file, garray_T *ga, int expand_options); +int wildmenu_translate_key(cmdline_info_T *cclp, int key, expand_T *xp, int did_wild_list); +int wildmenu_process_key(cmdline_info_T *cclp, int key, expand_T *xp); +void wildmenu_cleanup(cmdline_info_T *cclp); void f_getcompletion(typval_T *argvars, typval_T *rettv); /* vim: set ft=c : */ diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -755,6 +755,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1587, +/**/ 1586, /**/ 1585,