To: vim_dev@googlegroups.com Subject: Patch 8.2.1587 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.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) Files: src/cmdexpand.c, src/proto/cmdexpand.pro, src/ex_getln.c *** ../vim-8.2.1586/src/cmdexpand.c 2020-07-25 14:11:50.545128202 +0200 --- src/cmdexpand.c 2020-09-04 15:33:43.490037208 +0200 *************** *** 2614,2619 **** --- 2614,2868 ---- 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 *** ../vim-8.2.1586/src/proto/cmdexpand.pro 2020-01-05 14:38:37.110600924 +0100 --- src/proto/cmdexpand.pro 2020-09-04 15:33:31.810062466 +0200 *************** *** 9,13 **** --- 9,16 ---- 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 : */ *** ../vim-8.2.1586/src/ex_getln.c 2020-09-03 16:49:49.721754552 +0200 --- src/ex_getln.c 2020-09-04 15:33:28.642069304 +0200 *************** *** 44,52 **** 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); --- 44,49 ---- *************** *** 1064,1084 **** 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; #endif // free expanded names when finished walking through matches --- 1061,1067 ---- c = Ctrl_P; #ifdef FEAT_WILDMENU ! c = wildmenu_translate_key(&ccline, c, &xpc, did_wild_list); #endif // free expanded names when finished walking through matches *************** *** 1095,1284 **** 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; ! } #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 // CTRL-\ CTRL-N goes to Normal mode, CTRL-\ CTRL-G goes to Insert // mode when 'insertmode' is set, CTRL-\ e prompts for an expression. --- 1078,1090 ---- xpc.xp_context = EXPAND_NOTHING; wim_index = 0; #ifdef FEAT_WILDMENU ! wildmenu_cleanup(&ccline); #endif } #ifdef 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,3680 **** } } - #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 --- 3466,3471 ---- *** ../vim-8.2.1586/src/version.c 2020-09-04 14:41:17.621141198 +0200 --- src/version.c 2020-09-04 15:29:00.810636909 +0200 *************** *** 756,757 **** --- 756,759 ---- { /* Add new patch number below this line */ + /**/ + 1587, /**/ -- There are 2 kinds of people in my world: those who know Unix, Perl, Vim, GNU, Linux, etc, and those who know COBOL. It gets very difficult for me at parties, not knowing which group to socialise with :-) Sitaram Chamarty /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///