To: vim_dev@googlegroups.com Subject: Patch 8.2.1622 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.1622 Problem: Loop to handle keys for the command line is too long. Solution: Move code to functions. (Yegappan Lakshmanan, closes #6880) Files: src/ex_getln.c *** ../vim-8.2.1621/src/ex_getln.c 2020-09-04 15:37:27.865546317 +0200 --- src/ex_getln.c 2020-09-06 15:42:49.737157703 +0200 *************** *** 17,22 **** --- 17,27 ---- # define MAX(x,y) ((x) > (y) ? (x) : (y)) #endif + // Return value when handling keys in command-line mode. + #define CMDLINE_NOT_CHANGED 1 + #define CMDLINE_CHANGED 2 + #define GOTO_NORMAL_MODE 3 + // The current cmdline_info. It is initialized in getcmdline() and after that // used by other functions. When invoking getcmdline() recursively it needs // to be saved with save_cmdline() and restored with restore_cmdline(). *************** *** 763,768 **** --- 768,1250 ---- } /* + * Handle backspace, delete and CTRL-W keys in the command-line mode. + * Returns: + * CMDLINE_NOT_CHANGED - if the command line is not changed + * CMDLINE_CHANGED - if the command line is changed + * GOTO_NORMAL_MODE - go back to normal mode + */ + static int + cmdline_erase_chars( + int c, + int indent + #ifdef FEAT_SEARCH_EXTRA + , incsearch_state_T *isp + #endif + ) + { + int i; + int j; + + if (c == K_KDEL) + c = K_DEL; + + /* + * Delete current character is the same as backspace on next + * character, except at end of line. + */ + if (c == K_DEL && ccline.cmdpos != ccline.cmdlen) + ++ccline.cmdpos; + if (has_mbyte && c == K_DEL) + ccline.cmdpos += mb_off_next(ccline.cmdbuff, + ccline.cmdbuff + ccline.cmdpos); + if (ccline.cmdpos > 0) + { + char_u *p; + + j = ccline.cmdpos; + p = ccline.cmdbuff + j; + if (has_mbyte) + { + p = mb_prevptr(ccline.cmdbuff, p); + if (c == Ctrl_W) + { + while (p > ccline.cmdbuff && vim_isspace(*p)) + p = mb_prevptr(ccline.cmdbuff, p); + i = mb_get_class(p); + while (p > ccline.cmdbuff && mb_get_class(p) == i) + p = mb_prevptr(ccline.cmdbuff, p); + if (mb_get_class(p) != i) + p += (*mb_ptr2len)(p); + } + } + else if (c == Ctrl_W) + { + while (p > ccline.cmdbuff && vim_isspace(p[-1])) + --p; + i = vim_iswordc(p[-1]); + while (p > ccline.cmdbuff && !vim_isspace(p[-1]) + && vim_iswordc(p[-1]) == i) + --p; + } + else + --p; + ccline.cmdpos = (int)(p - ccline.cmdbuff); + ccline.cmdlen -= j - ccline.cmdpos; + i = ccline.cmdpos; + while (i < ccline.cmdlen) + ccline.cmdbuff[i++] = ccline.cmdbuff[j++]; + + // Truncate at the end, required for multi-byte chars. + ccline.cmdbuff[ccline.cmdlen] = NUL; + #ifdef FEAT_SEARCH_EXTRA + if (ccline.cmdlen == 0) + { + isp->search_start = isp->save_cursor; + // save view settings, so that the screen + // won't be restored at the wrong position + isp->old_viewstate = isp->init_viewstate; + } + #endif + redrawcmd(); + } + else if (ccline.cmdlen == 0 && c != Ctrl_W + && ccline.cmdprompt == NULL && indent == 0) + { + // In ex and debug mode it doesn't make sense to return. + if (exmode_active + #ifdef FEAT_EVAL + || ccline.cmdfirstc == '>' + #endif + ) + return CMDLINE_NOT_CHANGED; + + VIM_CLEAR(ccline.cmdbuff); // no commandline to return + if (!cmd_silent) + { + #ifdef FEAT_RIGHTLEFT + if (cmdmsg_rl) + msg_col = Columns; + else + #endif + msg_col = 0; + msg_putchar(' '); // delete ':' + } + #ifdef FEAT_SEARCH_EXTRA + if (ccline.cmdlen == 0) + isp->search_start = isp->save_cursor; + #endif + redraw_cmdline = TRUE; + return GOTO_NORMAL_MODE; + } + return CMDLINE_CHANGED; + } + + /* + * Handle the CTRL-^ key in the command-line mode and toggle the use of the + * language :lmap mappings and/or Input Method. + */ + static void + cmdline_toggle_langmap(long *b_im_ptr) + { + if (map_to_exists_mode((char_u *)"", LANGMAP, FALSE)) + { + // ":lmap" mappings exists, toggle use of mappings. + State ^= LANGMAP; + #ifdef HAVE_INPUT_METHOD + im_set_active(FALSE); // Disable input method + #endif + if (b_im_ptr != NULL) + { + if (State & LANGMAP) + *b_im_ptr = B_IMODE_LMAP; + else + *b_im_ptr = B_IMODE_NONE; + } + } + #ifdef HAVE_INPUT_METHOD + else + { + // There are no ":lmap" mappings, toggle IM. When + // 'imdisable' is set don't try getting the status, it's + // always off. + if ((p_imdisable && b_im_ptr != NULL) + ? *b_im_ptr == B_IMODE_IM : im_get_status()) + { + im_set_active(FALSE); // Disable input method + if (b_im_ptr != NULL) + *b_im_ptr = B_IMODE_NONE; + } + else + { + im_set_active(TRUE); // Enable input method + if (b_im_ptr != NULL) + *b_im_ptr = B_IMODE_IM; + } + } + #endif + if (b_im_ptr != NULL) + { + if (b_im_ptr == &curbuf->b_p_iminsert) + set_iminsert_global(); + else + set_imsearch_global(); + } + #ifdef CURSOR_SHAPE + ui_cursor_shape(); // may show different cursor shape + #endif + #if defined(FEAT_KEYMAP) + // Show/unshow value of 'keymap' in status lines later. + status_redraw_curbuf(); + #endif + } + + /* + * Handle the CTRL-R key in the command-line mode and insert the contents of a + * numbered or named register. + */ + static int + cmdline_insert_reg(int *gotesc UNUSED) + { + int i; + int c; + + #ifdef USE_ON_FLY_SCROLL + dont_scroll = TRUE; // disallow scrolling here + #endif + putcmdline('"', TRUE); + ++no_mapping; + ++allow_keys; + i = c = plain_vgetc(); // CTRL-R + if (i == Ctrl_O) + i = Ctrl_R; // CTRL-R CTRL-O == CTRL-R CTRL-R + if (i == Ctrl_R) + c = plain_vgetc(); // CTRL-R CTRL-R + extra_char = NUL; + --no_mapping; + --allow_keys; + #ifdef FEAT_EVAL + /* + * Insert the result of an expression. + * Need to save the current command line, to be able to enter + * a new one... + */ + new_cmdpos = -1; + if (c == '=') + { + if (ccline.cmdfirstc == '=' // can't do this recursively + || cmdline_star > 0) // or when typing a password + { + beep_flush(); + c = ESC; + } + else + c = get_expr_register(); + } + #endif + if (c != ESC) // use ESC to cancel inserting register + { + cmdline_paste(c, i == Ctrl_R, FALSE); + + #ifdef FEAT_EVAL + // When there was a serious error abort getting the + // command line. + if (aborting()) + { + *gotesc = TRUE; // will free ccline.cmdbuff after + // putting it in history + return GOTO_NORMAL_MODE; + } + #endif + KeyTyped = FALSE; // Don't do p_wc completion. + #ifdef FEAT_EVAL + if (new_cmdpos >= 0) + { + // set_cmdline_pos() was used + if (new_cmdpos > ccline.cmdlen) + ccline.cmdpos = ccline.cmdlen; + else + ccline.cmdpos = new_cmdpos; + } + #endif + } + redrawcmd(); + return CMDLINE_CHANGED; + } + + /* + * Handle the Left and Right mouse clicks in the command-line mode. + */ + static void + cmdline_left_right_mouse(int c, int *ignore_drag_release) + { + if (c == K_LEFTRELEASE || c == K_RIGHTRELEASE) + *ignore_drag_release = TRUE; + else + *ignore_drag_release = FALSE; + # ifdef FEAT_GUI + // When GUI is active, also move when 'mouse' is empty + if (!gui.in_use) + # endif + if (!mouse_has(MOUSE_COMMAND)) + return; + # ifdef FEAT_CLIPBOARD + if (mouse_row < cmdline_row && clip_star.available) + { + int button, is_click, is_drag; + + /* + * Handle modeless selection. + */ + button = get_mouse_button(KEY2TERMCAP1(c), + &is_click, &is_drag); + if (mouse_model_popup() && button == MOUSE_LEFT + && (mod_mask & MOD_MASK_SHIFT)) + { + // Translate shift-left to right button. + button = MOUSE_RIGHT; + mod_mask &= ~MOD_MASK_SHIFT; + } + clip_modeless(button, is_click, is_drag); + return; + } + # endif + + set_cmdspos(); + for (ccline.cmdpos = 0; ccline.cmdpos < ccline.cmdlen; + ++ccline.cmdpos) + { + int i; + + i = cmdline_charsize(ccline.cmdpos); + if (mouse_row <= cmdline_row + ccline.cmdspos / Columns + && mouse_col < ccline.cmdspos % Columns + i) + break; + if (has_mbyte) + { + // Count ">" for double-wide char that doesn't fit. + correct_cmdspos(ccline.cmdpos, i); + ccline.cmdpos += (*mb_ptr2len)(ccline.cmdbuff + + ccline.cmdpos) - 1; + } + ccline.cmdspos += i; + } + } + + /* + * Handle the Up, Down, Page Up, Page down, CTRL-N and CTRL-P key in the + * command-line mode. The pressed key is in 'c'. + * Returns: + * CMDLINE_NOT_CHANGED - if the command line is not changed + * CMDLINE_CHANGED - if the command line is changed + * GOTO_NORMAL_MODE - go back to normal mode + */ + static int + cmdline_browse_history( + int c, + int firstc, + char_u **curcmdstr, + int histype, + int *hiscnt_p, + expand_T *xp) + { + int i; + int j; + char_u *lookfor = *curcmdstr; + int hiscnt = *hiscnt_p; + int res; + + if (get_hislen() == 0 || firstc == NUL) // no history + return CMDLINE_NOT_CHANGED; + + i = hiscnt; + + // save current command string so it can be restored later + if (lookfor == NULL) + { + if ((lookfor = vim_strsave(ccline.cmdbuff)) == NULL) + return CMDLINE_NOT_CHANGED; + lookfor[ccline.cmdpos] = NUL; + } + + j = (int)STRLEN(lookfor); + for (;;) + { + // one step backwards + if (c == K_UP|| c == K_S_UP || c == Ctrl_P + || c == K_PAGEUP || c == K_KPAGEUP) + { + if (hiscnt == get_hislen()) // first time + hiscnt = *get_hisidx(histype); + else if (hiscnt == 0 && *get_hisidx(histype) + != get_hislen() - 1) + hiscnt = get_hislen() - 1; + else if (hiscnt != *get_hisidx(histype) + 1) + --hiscnt; + else // at top of list + { + hiscnt = i; + break; + } + } + else // one step forwards + { + // on last entry, clear the line + if (hiscnt == *get_hisidx(histype)) + { + hiscnt = get_hislen(); + break; + } + + // not on a history line, nothing to do + if (hiscnt == get_hislen()) + break; + if (hiscnt == get_hislen() - 1) // wrap around + hiscnt = 0; + else + ++hiscnt; + } + if (hiscnt < 0 || get_histentry(histype)[hiscnt].hisstr + == NULL) + { + hiscnt = i; + break; + } + if ((c != K_UP && c != K_DOWN) + || hiscnt == i + || STRNCMP(get_histentry(histype)[hiscnt].hisstr, + lookfor, (size_t)j) == 0) + break; + } + + if (hiscnt != i) // jumped to other entry + { + char_u *p; + int len; + int old_firstc; + + VIM_CLEAR(ccline.cmdbuff); + xp->xp_context = EXPAND_NOTHING; + if (hiscnt == get_hislen()) + p = lookfor; // back to the old one + else + p = get_histentry(histype)[hiscnt].hisstr; + + if (histype == HIST_SEARCH + && p != lookfor + && (old_firstc = p[STRLEN(p) + 1]) != firstc) + { + // Correct for the separator character used when + // adding the history entry vs the one used now. + // First loop: count length. + // Second loop: copy the characters. + for (i = 0; i <= 1; ++i) + { + len = 0; + for (j = 0; p[j] != NUL; ++j) + { + // Replace old sep with new sep, unless it is + // escaped. + if (p[j] == old_firstc + && (j == 0 || p[j - 1] != '\\')) + { + if (i > 0) + ccline.cmdbuff[len] = firstc; + } + else + { + // Escape new sep, unless it is already + // escaped. + if (p[j] == firstc + && (j == 0 || p[j - 1] != '\\')) + { + if (i > 0) + ccline.cmdbuff[len] = '\\'; + ++len; + } + if (i > 0) + ccline.cmdbuff[len] = p[j]; + } + ++len; + } + if (i == 0) + { + alloc_cmdbuff(len); + if (ccline.cmdbuff == NULL) + { + res = GOTO_NORMAL_MODE; + goto done; + } + } + } + ccline.cmdbuff[len] = NUL; + } + else + { + alloc_cmdbuff((int)STRLEN(p)); + if (ccline.cmdbuff == NULL) + { + res = GOTO_NORMAL_MODE; + goto done; + } + STRCPY(ccline.cmdbuff, p); + } + + ccline.cmdpos = ccline.cmdlen = (int)STRLEN(ccline.cmdbuff); + redrawcmd(); + res = CMDLINE_CHANGED; + goto done; + } + beep_flush(); + res = CMDLINE_NOT_CHANGED; + + done: + *curcmdstr = lookfor; + *hiscnt_p = hiscnt; + return res; + } + + /* * getcmdline() - accept a command line starting with firstc. * * firstc == ':' get ":" command line. *************** *** 1361,1458 **** case K_DEL: case K_KDEL: case Ctrl_W: ! if (c == K_KDEL) ! c = K_DEL; ! ! /* ! * delete current character is the same as backspace on next ! * character, except at end of line ! */ ! if (c == K_DEL && ccline.cmdpos != ccline.cmdlen) ! ++ccline.cmdpos; ! if (has_mbyte && c == K_DEL) ! ccline.cmdpos += mb_off_next(ccline.cmdbuff, ! ccline.cmdbuff + ccline.cmdpos); ! if (ccline.cmdpos > 0) ! { ! char_u *p; ! ! j = ccline.cmdpos; ! p = ccline.cmdbuff + j; ! if (has_mbyte) ! { ! p = mb_prevptr(ccline.cmdbuff, p); ! if (c == Ctrl_W) ! { ! while (p > ccline.cmdbuff && vim_isspace(*p)) ! p = mb_prevptr(ccline.cmdbuff, p); ! i = mb_get_class(p); ! while (p > ccline.cmdbuff && mb_get_class(p) == i) ! p = mb_prevptr(ccline.cmdbuff, p); ! if (mb_get_class(p) != i) ! p += (*mb_ptr2len)(p); ! } ! } ! else if (c == Ctrl_W) ! { ! while (p > ccline.cmdbuff && vim_isspace(p[-1])) ! --p; ! i = vim_iswordc(p[-1]); ! while (p > ccline.cmdbuff && !vim_isspace(p[-1]) ! && vim_iswordc(p[-1]) == i) ! --p; ! } ! else ! --p; ! ccline.cmdpos = (int)(p - ccline.cmdbuff); ! ccline.cmdlen -= j - ccline.cmdpos; ! i = ccline.cmdpos; ! while (i < ccline.cmdlen) ! ccline.cmdbuff[i++] = ccline.cmdbuff[j++]; ! ! // Truncate at the end, required for multi-byte chars. ! ccline.cmdbuff[ccline.cmdlen] = NUL; ! #ifdef FEAT_SEARCH_EXTRA ! if (ccline.cmdlen == 0) ! { ! is_state.search_start = is_state.save_cursor; ! // save view settings, so that the screen ! // won't be restored at the wrong position ! is_state.old_viewstate = is_state.init_viewstate; ! } ! #endif ! redrawcmd(); ! } ! else if (ccline.cmdlen == 0 && c != Ctrl_W ! && ccline.cmdprompt == NULL && indent == 0) ! { ! // In ex and debug mode it doesn't make sense to return. ! if (exmode_active ! #ifdef FEAT_EVAL ! || ccline.cmdfirstc == '>' ! #endif ! ) ! goto cmdline_not_changed; ! ! VIM_CLEAR(ccline.cmdbuff); // no commandline to return ! if (!cmd_silent) ! { ! #ifdef FEAT_RIGHTLEFT ! if (cmdmsg_rl) ! msg_col = Columns; ! else ! #endif ! msg_col = 0; ! msg_putchar(' '); // delete ':' ! } #ifdef FEAT_SEARCH_EXTRA ! if (ccline.cmdlen == 0) ! is_state.search_start = is_state.save_cursor; #endif ! redraw_cmdline = TRUE; ! goto returncmd; // back to cmd mode ! } ! goto cmdline_changed; case K_INS: case K_KINS: --- 1843,1858 ---- case K_DEL: case K_KDEL: case Ctrl_W: ! res = cmdline_erase_chars(c, indent #ifdef FEAT_SEARCH_EXTRA ! , &is_state #endif ! ); ! if (res == CMDLINE_NOT_CHANGED) ! goto cmdline_not_changed; ! else if (res == GOTO_NORMAL_MODE) ! goto returncmd; // back to cmd mode ! goto cmdline_changed; case K_INS: case K_KINS: *************** *** 1463,1518 **** goto cmdline_not_changed; case Ctrl_HAT: ! if (map_to_exists_mode((char_u *)"", LANGMAP, FALSE)) ! { ! // ":lmap" mappings exists, toggle use of mappings. ! State ^= LANGMAP; ! #ifdef HAVE_INPUT_METHOD ! im_set_active(FALSE); // Disable input method ! #endif ! if (b_im_ptr != NULL) ! { ! if (State & LANGMAP) ! *b_im_ptr = B_IMODE_LMAP; ! else ! *b_im_ptr = B_IMODE_NONE; ! } ! } ! #ifdef HAVE_INPUT_METHOD ! else ! { ! // There are no ":lmap" mappings, toggle IM. When ! // 'imdisable' is set don't try getting the status, it's ! // always off. ! if ((p_imdisable && b_im_ptr != NULL) ! ? *b_im_ptr == B_IMODE_IM : im_get_status()) ! { ! im_set_active(FALSE); // Disable input method ! if (b_im_ptr != NULL) ! *b_im_ptr = B_IMODE_NONE; ! } ! else ! { ! im_set_active(TRUE); // Enable input method ! if (b_im_ptr != NULL) ! *b_im_ptr = B_IMODE_IM; ! } ! } ! #endif ! if (b_im_ptr != NULL) ! { ! if (b_im_ptr == &curbuf->b_p_iminsert) ! set_iminsert_global(); ! else ! set_imsearch_global(); ! } ! #ifdef CURSOR_SHAPE ! ui_cursor_shape(); // may show different cursor shape ! #endif ! #if defined(FEAT_KEYMAP) ! // Show/unshow value of 'keymap' in status lines later. ! status_redraw_curbuf(); ! #endif goto cmdline_not_changed; // case '@': only in very old vi --- 1863,1869 ---- goto cmdline_not_changed; case Ctrl_HAT: ! cmdline_toggle_langmap(b_im_ptr); goto cmdline_not_changed; // case '@': only in very old vi *************** *** 1557,1622 **** goto returncmd; // back to cmd mode case Ctrl_R: // insert register ! #ifdef USE_ON_FLY_SCROLL ! dont_scroll = TRUE; // disallow scrolling here ! #endif ! putcmdline('"', TRUE); ! ++no_mapping; ! ++allow_keys; ! i = c = plain_vgetc(); // CTRL-R ! if (i == Ctrl_O) ! i = Ctrl_R; // CTRL-R CTRL-O == CTRL-R CTRL-R ! if (i == Ctrl_R) ! c = plain_vgetc(); // CTRL-R CTRL-R ! extra_char = NUL; ! --no_mapping; ! --allow_keys; ! #ifdef FEAT_EVAL ! /* ! * Insert the result of an expression. ! * Need to save the current command line, to be able to enter ! * a new one... ! */ ! new_cmdpos = -1; ! if (c == '=') ! { ! if (ccline.cmdfirstc == '=' // can't do this recursively ! || cmdline_star > 0) // or when typing a password ! { ! beep_flush(); ! c = ESC; ! } ! else ! c = get_expr_register(); ! } ! #endif ! if (c != ESC) // use ESC to cancel inserting register ! { ! cmdline_paste(c, i == Ctrl_R, FALSE); ! ! #ifdef FEAT_EVAL ! // When there was a serious error abort getting the ! // command line. ! if (aborting()) ! { ! gotesc = TRUE; // will free ccline.cmdbuff after ! // putting it in history ! goto returncmd; // back to cmd mode ! } ! #endif ! KeyTyped = FALSE; // Don't do p_wc completion. ! #ifdef FEAT_EVAL ! if (new_cmdpos >= 0) ! { ! // set_cmdline_pos() was used ! if (new_cmdpos > ccline.cmdlen) ! ccline.cmdpos = ccline.cmdlen; ! else ! ccline.cmdpos = new_cmdpos; ! } ! #endif ! } ! redrawcmd(); goto cmdline_changed; case Ctrl_D: --- 1908,1918 ---- goto returncmd; // back to cmd mode case Ctrl_R: // insert register ! res = cmdline_insert_reg(&gotesc); ! if (res == CMDLINE_NOT_CHANGED) ! goto cmdline_not_changed; ! else if (res == GOTO_NORMAL_MODE) ! goto returncmd; goto cmdline_changed; case Ctrl_D: *************** *** 1725,1779 **** // FALLTHROUGH case K_LEFTMOUSE: case K_RIGHTMOUSE: ! if (c == K_LEFTRELEASE || c == K_RIGHTRELEASE) ! ignore_drag_release = TRUE; ! else ! ignore_drag_release = FALSE; ! # ifdef FEAT_GUI ! // When GUI is active, also move when 'mouse' is empty ! if (!gui.in_use) ! # endif ! if (!mouse_has(MOUSE_COMMAND)) ! goto cmdline_not_changed; // Ignore mouse ! # ifdef FEAT_CLIPBOARD ! if (mouse_row < cmdline_row && clip_star.available) ! { ! int button, is_click, is_drag; ! ! /* ! * Handle modeless selection. ! */ ! button = get_mouse_button(KEY2TERMCAP1(c), ! &is_click, &is_drag); ! if (mouse_model_popup() && button == MOUSE_LEFT ! && (mod_mask & MOD_MASK_SHIFT)) ! { ! // Translate shift-left to right button. ! button = MOUSE_RIGHT; ! mod_mask &= ~MOD_MASK_SHIFT; ! } ! clip_modeless(button, is_click, is_drag); ! goto cmdline_not_changed; ! } ! # endif ! ! set_cmdspos(); ! for (ccline.cmdpos = 0; ccline.cmdpos < ccline.cmdlen; ! ++ccline.cmdpos) ! { ! i = cmdline_charsize(ccline.cmdpos); ! if (mouse_row <= cmdline_row + ccline.cmdspos / Columns ! && mouse_col < ccline.cmdspos % Columns + i) ! break; ! if (has_mbyte) ! { ! // Count ">" for double-wide char that doesn't fit. ! correct_cmdspos(ccline.cmdpos, i); ! ccline.cmdpos += (*mb_ptr2len)(ccline.cmdbuff ! + ccline.cmdpos) - 1; ! } ! ccline.cmdspos += i; ! } goto cmdline_not_changed; // Mouse scroll wheel: ignored here --- 2021,2027 ---- // FALLTHROUGH case K_LEFTMOUSE: case K_RIGHTMOUSE: ! cmdline_left_right_mouse(c, &ignore_drag_release); goto cmdline_not_changed; // Mouse scroll wheel: ignored here *************** *** 1877,2017 **** case K_KPAGEUP: case K_PAGEDOWN: case K_KPAGEDOWN: ! if (get_hislen() == 0 || firstc == NUL) // no history ! goto cmdline_not_changed; ! ! i = hiscnt; ! ! // save current command string so it can be restored later ! if (lookfor == NULL) ! { ! if ((lookfor = vim_strsave(ccline.cmdbuff)) == NULL) ! goto cmdline_not_changed; ! lookfor[ccline.cmdpos] = NUL; ! } ! ! j = (int)STRLEN(lookfor); ! for (;;) ! { ! // one step backwards ! if (c == K_UP|| c == K_S_UP || c == Ctrl_P ! || c == K_PAGEUP || c == K_KPAGEUP) ! { ! if (hiscnt == get_hislen()) // first time ! hiscnt = *get_hisidx(histype); ! else if (hiscnt == 0 && *get_hisidx(histype) ! != get_hislen() - 1) ! hiscnt = get_hislen() - 1; ! else if (hiscnt != *get_hisidx(histype) + 1) ! --hiscnt; ! else // at top of list ! { ! hiscnt = i; ! break; ! } ! } ! else // one step forwards ! { ! // on last entry, clear the line ! if (hiscnt == *get_hisidx(histype)) ! { ! hiscnt = get_hislen(); ! break; ! } ! ! // not on a history line, nothing to do ! if (hiscnt == get_hislen()) ! break; ! if (hiscnt == get_hislen() - 1) // wrap around ! hiscnt = 0; ! else ! ++hiscnt; ! } ! if (hiscnt < 0 || get_histentry(histype)[hiscnt].hisstr ! == NULL) ! { ! hiscnt = i; ! break; ! } ! if ((c != K_UP && c != K_DOWN) ! || hiscnt == i ! || STRNCMP(get_histentry(histype)[hiscnt].hisstr, ! lookfor, (size_t)j) == 0) ! break; ! } ! ! if (hiscnt != i) // jumped to other entry ! { ! char_u *p; ! int len; ! int old_firstc; ! ! VIM_CLEAR(ccline.cmdbuff); ! xpc.xp_context = EXPAND_NOTHING; ! if (hiscnt == get_hislen()) ! p = lookfor; // back to the old one ! else ! p = get_histentry(histype)[hiscnt].hisstr; ! ! if (histype == HIST_SEARCH ! && p != lookfor ! && (old_firstc = p[STRLEN(p) + 1]) != firstc) ! { ! // Correct for the separator character used when ! // adding the history entry vs the one used now. ! // First loop: count length. ! // Second loop: copy the characters. ! for (i = 0; i <= 1; ++i) ! { ! len = 0; ! for (j = 0; p[j] != NUL; ++j) ! { ! // Replace old sep with new sep, unless it is ! // escaped. ! if (p[j] == old_firstc ! && (j == 0 || p[j - 1] != '\\')) ! { ! if (i > 0) ! ccline.cmdbuff[len] = firstc; ! } ! else ! { ! // Escape new sep, unless it is already ! // escaped. ! if (p[j] == firstc ! && (j == 0 || p[j - 1] != '\\')) ! { ! if (i > 0) ! ccline.cmdbuff[len] = '\\'; ! ++len; ! } ! if (i > 0) ! ccline.cmdbuff[len] = p[j]; ! } ! ++len; ! } ! if (i == 0) ! { ! alloc_cmdbuff(len); ! if (ccline.cmdbuff == NULL) ! goto returncmd; ! } ! } ! ccline.cmdbuff[len] = NUL; ! } ! else ! { ! alloc_cmdbuff((int)STRLEN(p)); ! if (ccline.cmdbuff == NULL) ! goto returncmd; ! STRCPY(ccline.cmdbuff, p); ! } ! ! ccline.cmdpos = ccline.cmdlen = (int)STRLEN(ccline.cmdbuff); ! redrawcmd(); goto cmdline_changed; ! } ! beep_flush(); goto cmdline_not_changed; #ifdef FEAT_SEARCH_EXTRA --- 2125,2136 ---- case K_KPAGEUP: case K_PAGEDOWN: case K_KPAGEDOWN: ! res = cmdline_browse_history(c, firstc, &lookfor, histype, ! &hiscnt, &xpc); ! if (res == CMDLINE_CHANGED) goto cmdline_changed; ! else if (res == GOTO_NORMAL_MODE) ! goto returncmd; goto cmdline_not_changed; #ifdef FEAT_SEARCH_EXTRA *** ../vim-8.2.1621/src/version.c 2020-09-06 15:14:42.217505521 +0200 --- src/version.c 2020-09-06 15:39:46.629413283 +0200 *************** *** 756,757 **** --- 756,759 ---- { /* Add new patch number below this line */ + /**/ + 1622, /**/ -- Mental Floss prevents moral decay! /// 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 ///