diff options
author | zeertzjq <zeertzjq@outlook.com> | 2022-08-21 09:18:47 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-08-21 09:18:47 +0800 |
commit | 61ff37952ab95bc8362003bec0ff9acf565e1b09 (patch) | |
tree | b0edcc1e1f2408719121e9bae36bc517689d3cc3 | |
parent | 741ef87876d86ef7c6f64297a47aba15613e78da (diff) | |
download | rneovim-61ff37952ab95bc8362003bec0ff9acf565e1b09.tar.gz rneovim-61ff37952ab95bc8362003bec0ff9acf565e1b09.tar.bz2 rneovim-61ff37952ab95bc8362003bec0ff9acf565e1b09.zip |
vim-patch:8.2.1587: loop for handling keys for the command line is too long (#19868)
Problem: Loop for handling keys for the command line is too long.
Solution: Move wild menu handling to separate functions. (Yegappan
Lakshmanan, closes vim/vim#6856)
https://github.com/vim/vim/commit/eadee486c70946ad0e1746d77898d6f4f4acc817
-rw-r--r-- | src/nvim/cmdexpand.c | 233 | ||||
-rw-r--r-- | src/nvim/cmdexpand.h | 1 | ||||
-rw-r--r-- | src/nvim/ex_getln.c | 205 |
3 files changed, 233 insertions, 206 deletions
diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index 28806094d6..dd5251e761 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -10,6 +10,7 @@ #include "nvim/charset.h" #include "nvim/cmdexpand.h" #include "nvim/cmdhist.h" +#include "nvim/drawscreen.h" #include "nvim/eval.h" #include "nvim/eval/funcs.h" #include "nvim/eval/userfunc.h" @@ -40,6 +41,7 @@ #include "nvim/ui.h" #include "nvim/usercmd.h" #include "nvim/vim.h" +#include "nvim/window.h" /// Type used by ExpandGeneric() typedef char *(*CompleteListItemGetter)(expand_T *, int); @@ -53,15 +55,13 @@ typedef void *(*user_expand_func_T)(const char_u *, int, typval_T *); static int cmd_showtail; ///< Only show path tail in lists ? -// TODO(zeertzjq): make these four variables static in cmdexpand.c - /// "compl_match_array" points the currently displayed list of entries in the /// popup menu. It is NULL when there is no popup menu. -pumitem_T *compl_match_array = NULL; -int compl_match_arraysize; +pumitem_T *compl_match_array = NULL; // TODO(zeertzjq): make this static in cmdexpand.c +static int compl_match_arraysize; /// First column in cmdline of the matched item for completion. -int compl_startcol; -int compl_selected; +static int compl_startcol; +static int compl_selected; static int sort_func_compare(const void *s1, const void *s2) { @@ -2509,6 +2509,227 @@ void globpath(char *path, char_u *file, garray_T *ga, int expand_options) xfree(buf); } +/// Translate some keys pressed when 'wildmenu' is used. +int wildmenu_translate_key(CmdlineInfo *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(CmdlineInfo *cclp, int from) +{ + assert(cclp->cmdpos <= cclp->cmdlen); + memmove(cclp->cmdbuff + from, cclp->cmdbuff + cclp->cmdpos, + (size_t)cclp->cmdlen - (size_t)cclp->cmdpos + 1); + cclp->cmdlen -= cclp->cmdpos - from; + cclp->cmdpos = from; +} + +/// Handle a key pressed when wild menu is displayed +int wildmenu_process_key(CmdlineInfo *cclp, int key, expand_T *xp) +{ + int c = key; + + 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 = (int)p_wc; + KeyTyped = true; // in case the key was mapped + } else if (c == K_UP) { + // Hitting <Up>: Remove one submenu name in front of the + // cursor + int found = false; + + int j = (int)((char_u *)xp->xp_pattern - cclp->cmdbuff); + int 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 = (int)p_wc; + KeyTyped = true; // in case the key was mapped + 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 = (int)p_wc; + KeyTyped = true; // in case the key was mapped + } 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; + + int j = cclp->cmdpos; + int i = (int)((char_u *)xp->xp_pattern - cclp->cmdbuff); + while (--j > i) { + j -= utf_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 = (int)p_wc; + KeyTyped = true; // in case the key was mapped + } + } else if (c == K_UP) { + // go up a directory + int found = false; + + int j = cclp->cmdpos - 1; + int i = (int)((char_u *)xp->xp_pattern - cclp->cmdbuff); + while (--j > i) { + j -= utf_head_off(cclp->cmdbuff, cclp->cmdbuff + j); + if (vim_ispathsep(cclp->cmdbuff[j]) +#ifdef BACKSLASH_IN_FILENAME + && vim_strchr((const 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(tarruda): 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 = (int)p_wc; + KeyTyped = true; + } + } + + return c; +} + +/// Free expanded names when finished walking through the matches +void wildmenu_cleanup(CmdlineInfo *cclp) +{ + if (!p_wmnu || wild_menu_showing == 0) { + return; + } + + const bool skt = KeyTyped; + int old_RedrawingDisabled = RedrawingDisabled; + + if (cclp->input_fn) { + RedrawingDisabled = 0; + } + + if (wild_menu_showing == WM_SCROLLED) { + // Entered command line, move it up + cmdline_row--; + redrawcmd(); + wild_menu_showing = 0; + } 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; + wild_menu_showing = 0; + // don't redraw statusline if WM_LIST is showing + } else if (wild_menu_showing != WM_LIST) { + win_redraw_last_status(topframe); + wild_menu_showing = 0; // must be before redraw_statuslines #8385 + redraw_statuslines(); + } else { + wild_menu_showing = 0; + } + KeyTyped = skt; + if (cclp->input_fn) { + RedrawingDisabled = old_RedrawingDisabled; + } +} + /// "getcompletion()" function void f_getcompletion(typval_T *argvars, typval_T *rettv, FunPtr fptr) { diff --git a/src/nvim/cmdexpand.h b/src/nvim/cmdexpand.h index f534a2e0d3..93e91af169 100644 --- a/src/nvim/cmdexpand.h +++ b/src/nvim/cmdexpand.h @@ -2,6 +2,7 @@ #define NVIM_CMDEXPAND_H #include "nvim/eval/typval.h" +#include "nvim/ex_getln.h" #include "nvim/garray.h" #include "nvim/types.h" diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index c14eca6604..ec6c4af18a 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -170,12 +170,7 @@ static Array cmdline_block = ARRAY_DICT_INIT; /// user interrupting highlight function to not interrupt command-line. static bool getln_interrupted_highlight = false; -// TODO(zeertzjq): make these four variables static in cmdexpand.c - -extern pumitem_T *compl_match_array; -extern int compl_match_arraysize; -extern int compl_startcol; -extern int compl_selected; +extern pumitem_T *compl_match_array; // TODO(zeertzjq): make this static in cmdexpand.c #ifdef INCLUDE_GENERATED_DECLARATIONS # include "ex_getln.c.generated.h" @@ -1028,14 +1023,8 @@ static int command_line_execute(VimState *state, int key) s->c = Ctrl_P; } - // Special translations for 'wildmenu' - if (s->did_wild_list && p_wmnu) { - if (s->c == K_LEFT) { - s->c = Ctrl_P; - } else if (s->c == K_RIGHT) { - s->c = Ctrl_N; - } - } + s->c = wildmenu_translate_key(&ccline, s->c, &s->xpc, s->did_wild_list); + if (compl_match_array || s->did_wild_list) { if (s->c == Ctrl_E) { s->res = nextwild(&s->xpc, WILD_CANCEL, WILD_NO_BEEP, @@ -1047,15 +1036,6 @@ static int command_line_execute(VimState *state, int key) } } - // Hitting CR after "emenu Name.": complete submenu - if (s->xpc.xp_context == EXPAND_MENUNAMES && p_wmnu - && ccline.cmdpos > 1 - && ccline.cmdbuff[ccline.cmdpos - 1] == '.' - && ccline.cmdbuff[ccline.cmdpos - 2] != '\\' - && (s->c == '\n' || s->c == '\r' || s->c == K_KENTER)) { - s->c = K_DOWN; - } - // free expanded names when finished walking through matches if (!(s->c == p_wc && KeyTyped) && s->c != p_wcm && s->c != Ctrl_Z && s->c != Ctrl_N && s->c != Ctrl_P && s->c != Ctrl_A @@ -1072,175 +1052,10 @@ static int command_line_execute(VimState *state, int key) s->xpc.xp_context = EXPAND_NOTHING; } s->wim_index = 0; - if (p_wmnu && wild_menu_showing != 0) { - const bool 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(); - wild_menu_showing = 0; - } 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; - wild_menu_showing = 0; - // don't redraw statusline if WM_LIST is showing - } else if (wild_menu_showing != WM_LIST) { - win_redraw_last_status(topframe); - wild_menu_showing = 0; // must be before redraw_statuslines #8385 - redraw_statuslines(); - } else { - wild_menu_showing = 0; - } - KeyTyped = skt; - if (ccline.input_fn) { - RedrawingDisabled = old_RedrawingDisabled; - } - } - } - - // Special translations for 'wildmenu' - if (s->xpc.xp_context == EXPAND_MENUNAMES && p_wmnu) { - // Hitting <Down> after "emenu Name.": complete submenu - if (s->c == K_DOWN && ccline.cmdpos > 0 - && ccline.cmdbuff[ccline.cmdpos - 1] == '.') { - s->c = (int)p_wc; - KeyTyped = true; // in case the key was mapped - } else if (s->c == K_UP) { - // Hitting <Up>: Remove one submenu name in front of the - // cursor - int found = false; - - int j = (int)((char_u *)s->xpc.xp_pattern - ccline.cmdbuff); - int 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); - } - s->c = (int)p_wc; - KeyTyped = true; // in case the key was mapped - s->xpc.xp_context = EXPAND_NOTHING; - } + wildmenu_cleanup(&ccline); } - if ((s->xpc.xp_context == EXPAND_FILES - || s->xpc.xp_context == EXPAND_DIRECTORIES - || s->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 (s->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 - s->c = (int)p_wc; - KeyTyped = true; // in case the key was mapped - } else if (STRNCMP(s->xpc.xp_pattern, upseg + 1, 3) == 0 - && s->c == K_DOWN) { - // If in a direct ancestor, strip off one ../ to go down - int found = false; - - int j = ccline.cmdpos; - int i = (int)((char_u *)s->xpc.xp_pattern - ccline.cmdbuff); - while (--j > i) { - j -= utf_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); - s->c = (int)p_wc; - KeyTyped = true; // in case the key was mapped - } - } else if (s->c == K_UP) { - // go up a directory - int found = false; - - int j = ccline.cmdpos - 1; - int i = (int)((char_u *)s->xpc.xp_pattern - ccline.cmdbuff); - while (--j > i) { - j -= utf_head_off(ccline.cmdbuff, ccline.cmdbuff + j); - if (vim_ispathsep(ccline.cmdbuff[j]) -#ifdef BACKSLASH_IN_FILENAME - && vim_strchr((const 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(tarruda): 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. - s->c = (int)p_wc; - KeyTyped = true; - } - } + s->c = wildmenu_process_key(&ccline, s->c, &s->xpc); // CTRL-\ CTRL-N goes to Normal mode, CTRL-\ e prompts for an expression. if (s->c == Ctrl_BSL) { @@ -3749,16 +3564,6 @@ void cmdline_paste_str(char_u *s, int literally) } } -/// Delete characters on the command line, from "from" to the current position. -static void cmdline_del(int from) -{ - assert(ccline.cmdpos <= ccline.cmdlen); - memmove(ccline.cmdbuff + from, ccline.cmdbuff + ccline.cmdpos, - (size_t)ccline.cmdlen - (size_t)ccline.cmdpos + 1); - ccline.cmdlen -= ccline.cmdpos - from; - ccline.cmdpos = from; -} - // This function is called when the screen size changes and with incremental // search and in other situations where the command line may have been // overwritten. |