# HG changeset patch # User Christian Brabandt # Date 1533932105 -7200 # Node ID 4825955cb70626f50c6f3950b876a33836761eda # Parent f6cb0b08aedbc471c8e9fc9d76d57b5f620049f5 patch 8.1.0265: the getcmdline() function is way too big commit https://github.com/vim/vim/commit/0ee81cb63876e6ec1b2a6e0125295b43f1c63c7d Author: Bram Moolenaar Date: Fri Aug 10 22:07:32 2018 +0200 patch 8.1.0265: the getcmdline() function is way too big Problem: The getcmdline() function is way too big. Solution: Factor out the incremental search highlighting. diff --git a/src/ex_getln.c b/src/ex_getln.c --- a/src/ex_getln.c +++ b/src/ex_getln.c @@ -141,9 +141,6 @@ static int #endif sort_func_compare(const void *s1, const void *s2); #endif -#ifdef FEAT_SEARCH_EXTRA -static void set_search_match(pos_T *t); -#endif static void @@ -185,9 +182,8 @@ empty_pattern(char_u *p) n -= 2; return n == 0 || (n >= 2 && p[n - 2] == '\\' && p[n - 1] == '|'); } -#endif - -#ifdef FEAT_SEARCH_EXTRA + +// Struct to store the viewstate during 'incsearch' highlighting. typedef struct { colnr_T vs_curswant; colnr_T vs_leftcol; @@ -224,6 +220,334 @@ restore_viewstate(viewstate_T *vs) curwin->w_botline = vs->vs_botline; curwin->w_empty_rows = vs->vs_empty_rows; } + +// Struct to store the state of 'incsearch' highlighting. +typedef struct { + pos_T search_start; // where 'incsearch' starts searching + pos_T save_cursor; + viewstate_T init_viewstate; + viewstate_T old_viewstate; + pos_T match_start; + pos_T match_end; + int did_incsearch; + int incsearch_postponed; +} incsearch_state_T; + + static void +init_incsearch_state(incsearch_state_T *is_state) +{ + is_state->match_start = curwin->w_cursor; + is_state->did_incsearch = FALSE; + is_state->incsearch_postponed = FALSE; + CLEAR_POS(&is_state->match_end); + is_state->save_cursor = curwin->w_cursor; // may be restored later + is_state->search_start = curwin->w_cursor; + save_viewstate(&is_state->init_viewstate); + save_viewstate(&is_state->old_viewstate); +} + +/* + * First move cursor to end of match, then to the start. This + * moves the whole match onto the screen when 'nowrap' is set. + */ + static void +set_search_match(pos_T *t) +{ + t->lnum += search_match_lines; + t->col = search_match_endcol; + if (t->lnum > curbuf->b_ml.ml_line_count) + { + t->lnum = curbuf->b_ml.ml_line_count; + coladvance((colnr_T)MAXCOL); + } +} + +/* + * Return TRUE when 'incsearch' highlighting is to be done. + */ + static int +do_incsearch_highlighting(int firstc) +{ + return p_is && !cmd_silent && (firstc == '/' || firstc == '?'); +} + +/* + * Do 'incsearch' highlighting if desired. + */ + static void +may_do_incsearch_highlighting( + int firstc, + long count, + incsearch_state_T *is_state) +{ + int i; + pos_T end_pos; + struct cmdline_info save_ccline; +#ifdef FEAT_RELTIME + proftime_T tm; +#endif + + if (!do_incsearch_highlighting(firstc)) + return; + + // If there is a character waiting, search and redraw later. + if (char_avail()) + { + is_state->incsearch_postponed = TRUE; + return; + } + is_state->incsearch_postponed = FALSE; + + // start at old position + curwin->w_cursor = is_state->search_start; + save_last_search_pattern(); + + // If there is no command line, don't do anything. + if (ccline.cmdlen == 0) + { + i = 0; + set_no_hlsearch(TRUE); // turn off previous highlight + redraw_all_later(SOME_VALID); + } + else + { + int search_flags = SEARCH_OPT + SEARCH_NOOF + SEARCH_PEEK; + + cursor_off(); // so the user knows we're busy + out_flush(); + ++emsg_off; // so it doesn't beep if bad expr +#ifdef FEAT_RELTIME + // Set the time limit to half a second. + profile_setlimit(500L, &tm); +#endif + if (!p_hls) + search_flags += SEARCH_KEEP; + i = do_search(NULL, firstc, ccline.cmdbuff, count, search_flags, +#ifdef FEAT_RELTIME + &tm, NULL +#else + NULL, NULL +#endif + ); + --emsg_off; + + // if interrupted while searching, behave like it failed + if (got_int) + { + (void)vpeekc(); // remove from input stream + got_int = FALSE; // don't abandon the command line + i = 0; + } + else if (char_avail()) + // cancelled searching because a char was typed + is_state->incsearch_postponed = TRUE; + } + if (i != 0) + highlight_match = TRUE; // highlight position + else + highlight_match = FALSE; // remove highlight + + // First restore the old curwin values, so the screen is positioned in the + // same way as the actual search command. + restore_viewstate(&is_state->old_viewstate); + changed_cline_bef_curs(); + update_topline(); + + if (i != 0) + { + pos_T save_pos = curwin->w_cursor; + + is_state->match_start = curwin->w_cursor; + set_search_match(&curwin->w_cursor); + validate_cursor(); + end_pos = curwin->w_cursor; + is_state->match_end = end_pos; + curwin->w_cursor = save_pos; + } + else + end_pos = curwin->w_cursor; // shutup gcc 4 + + // Disable 'hlsearch' highlighting if the pattern matches everything. + // Avoids a flash when typing "foo\|". + if (empty_pattern(ccline.cmdbuff)) + set_no_hlsearch(TRUE); + + validate_cursor(); + // May redraw the status line to show the cursor position. + if (p_ru && curwin->w_status_height > 0) + curwin->w_redr_status = TRUE; + + save_cmdline(&save_ccline); + update_screen(SOME_VALID); + restore_cmdline(&save_ccline); + restore_last_search_pattern(); + + // Leave it at the end to make CTRL-R CTRL-W work. + if (i != 0) + curwin->w_cursor = end_pos; + + msg_starthere(); + redrawcmdline(); + is_state->did_incsearch = TRUE; +} + +/* + * May adjust 'incsearch' highlighting for typing CTRL-G and CTRL-T, go to next + * or previous match. + * Returns FAIL when jumping to cmdline_not_changed; + */ + static int +may_adjust_incsearch_highlighting( + int firstc, + long count, + incsearch_state_T *is_state, + int c) +{ + pos_T t; + char_u *pat; + int search_flags = SEARCH_NOOF; + int i; + + if (!do_incsearch_highlighting(firstc)) + return OK; + if (ccline.cmdlen == 0) + return FAIL; + + if (firstc == ccline.cmdbuff[0]) + pat = last_search_pattern(); + else + pat = ccline.cmdbuff; + + save_last_search_pattern(); + cursor_off(); + out_flush(); + if (c == Ctrl_G) + { + t = is_state->match_end; + if (LT_POS(is_state->match_start, is_state->match_end)) + // Start searching at the end of the match not at the beginning of + // the next column. + (void)decl(&t); + search_flags += SEARCH_COL; + } + else + t = is_state->match_start; + if (!p_hls) + search_flags += SEARCH_KEEP; + ++emsg_off; + i = searchit(curwin, curbuf, &t, + c == Ctrl_G ? FORWARD : BACKWARD, + pat, count, search_flags, + RE_SEARCH, 0, NULL, NULL); + --emsg_off; + if (i) + { + is_state->search_start = is_state->match_start; + is_state->match_end = t; + is_state->match_start = t; + if (c == Ctrl_T && firstc == '/') + { + // Move just before the current match, so that when nv_search + // finishes the cursor will be put back on the match. + is_state->search_start = t; + (void)decl(&is_state->search_start); + } + else if (c == Ctrl_G && firstc == '?') + { + // Move just after the current match, so that when nv_search + // finishes the cursor will be put back on the match. + is_state->search_start = t; + (void)incl(&is_state->search_start); + } + if (LT_POS(t, is_state->search_start) && c == Ctrl_G) + { + // wrap around + is_state->search_start = t; + if (firstc == '?') + (void)incl(&is_state->search_start); + else + (void)decl(&is_state->search_start); + } + + set_search_match(&is_state->match_end); + curwin->w_cursor = is_state->match_start; + changed_cline_bef_curs(); + update_topline(); + validate_cursor(); + highlight_match = TRUE; + save_viewstate(&is_state->old_viewstate); + update_screen(NOT_VALID); + redrawcmdline(); + } + else + vim_beep(BO_ERROR); + restore_last_search_pattern(); + return FAIL; +} + +/* + * When CTRL-L typed: add character from the match to the pattern. + * May set "*c" to the added character. + * Return OK when jumping to cmdline_not_changed. + */ + static int +may_add_char_to_search(int firstc, int *c, incsearch_state_T *is_state) +{ + if (!do_incsearch_highlighting(firstc)) + return FAIL; + + // Add a character from under the cursor for 'incsearch'. + if (is_state->did_incsearch) + { + curwin->w_cursor = is_state->match_end; + if (!EQUAL_POS(curwin->w_cursor, is_state->search_start)) + { + *c = gchar_cursor(); + + // If 'ignorecase' and 'smartcase' are set and the + // command line has no uppercase characters, convert + // the character to lowercase. + if (p_ic && p_scs && !pat_has_uppercase(ccline.cmdbuff)) + *c = MB_TOLOWER(*c); + if (*c != NUL) + { + if (*c == firstc || vim_strchr((char_u *)( + p_magic ? "\\~^$.*[" : "\\^$"), *c) != NULL) + { + // put a backslash before special characters + stuffcharReadbuff(*c); + *c = '\\'; + } + return FAIL; + } + } + } + return OK; +} + + static void +finish_incsearch_highlighting(int gotesc, incsearch_state_T *is_state) +{ + if (is_state->did_incsearch) + { + if (gotesc) + curwin->w_cursor = is_state->save_cursor; + else + { + if (!EQUAL_POS(is_state->save_cursor, is_state->search_start)) + { + // put the '" mark at the original position + curwin->w_cursor = is_state->save_cursor; + setpcmark(); + } + curwin->w_cursor = is_state->search_start; + } + restore_viewstate(&is_state->old_viewstate); + highlight_match = FALSE; + validate_cursor(); /* needed for TAB */ + redraw_all_later(SOME_VALID); + } +} #endif /* @@ -262,14 +586,7 @@ getcmdline( int histype; /* history type to be used */ #endif #ifdef FEAT_SEARCH_EXTRA - pos_T search_start; /* where 'incsearch' starts searching */ - pos_T save_cursor; - viewstate_T init_viewstate; - viewstate_T old_viewstate; - pos_T match_start = curwin->w_cursor; - pos_T match_end; - int did_incsearch = FALSE; - int incsearch_postponed = FALSE; + incsearch_state_T is_state; #endif int did_wild_list = FALSE; /* did wild_list() recently */ int wim_index = 0; /* index in wim_flags[] */ @@ -287,7 +604,7 @@ getcmdline( #endif expand_T xpc; long *b_im_ptr = NULL; -#if defined(FEAT_WILDMENU) || defined(FEAT_EVAL) || defined(FEAT_SEARCH_EXTRA) +#if defined(FEAT_WILDMENU) || defined(FEAT_EVAL) /* Everything that may work recursively should save and restore the * current command line in save_ccline. That includes update_screen(), a * custom status line may invoke ":normal". */ @@ -309,12 +626,9 @@ getcmdline( #endif ccline.overstrike = FALSE; /* always start in insert mode */ + #ifdef FEAT_SEARCH_EXTRA - CLEAR_POS(&match_end); - save_cursor = curwin->w_cursor; /* may be restored later */ - search_start = curwin->w_cursor; - save_viewstate(&init_viewstate); - save_viewstate(&old_viewstate); + init_incsearch_state(&is_state); #endif /* @@ -1089,10 +1403,10 @@ getcmdline( #ifdef FEAT_SEARCH_EXTRA if (ccline.cmdlen == 0) { - search_start = save_cursor; + is_state.search_start = is_state.save_cursor; /* save view settings, so that the screen * won't be restored at the wrong position */ - old_viewstate = init_viewstate; + is_state.old_viewstate = is_state.init_viewstate; } #endif redrawcmd(); @@ -1121,7 +1435,7 @@ getcmdline( } #ifdef FEAT_SEARCH_EXTRA if (ccline.cmdlen == 0) - search_start = save_cursor; + is_state.search_start = is_state.save_cursor; #endif redraw_cmdline = TRUE; goto returncmd; /* back to cmd mode */ @@ -1208,7 +1522,7 @@ getcmdline( ccline.cmdbuff[ccline.cmdlen] = NUL; #ifdef FEAT_SEARCH_EXTRA if (ccline.cmdlen == 0) - search_start = save_cursor; + is_state.search_start = is_state.save_cursor; #endif redrawcmd(); goto cmdline_changed; @@ -1545,38 +1859,8 @@ getcmdline( case Ctrl_L: #ifdef FEAT_SEARCH_EXTRA - if (p_is && !cmd_silent && (firstc == '/' || firstc == '?')) - { - /* Add a character from under the cursor for 'incsearch' */ - if (did_incsearch) - { - curwin->w_cursor = match_end; - if (!EQUAL_POS(curwin->w_cursor, search_start)) - { - c = gchar_cursor(); - /* If 'ignorecase' and 'smartcase' are set and the - * command line has no uppercase characters, convert - * the character to lowercase */ - if (p_ic && p_scs - && !pat_has_uppercase(ccline.cmdbuff)) - c = MB_TOLOWER(c); - if (c != NUL) - { - if (c == firstc || vim_strchr((char_u *)( - p_magic ? "\\~^$.*[" : "\\^$"), c) - != NULL) - { - /* put a backslash before special - * characters */ - stuffcharReadbuff(c); - c = '\\'; - } - break; - } - } - } + if (may_add_char_to_search(firstc, &c, &is_state) == OK) goto cmdline_not_changed; - } #endif /* completion: longest common part */ @@ -1742,88 +2026,9 @@ getcmdline( #ifdef FEAT_SEARCH_EXTRA case Ctrl_G: /* next match */ case Ctrl_T: /* previous match */ - if (p_is && !cmd_silent && (firstc == '/' || firstc == '?')) - { - pos_T t; - char_u *pat; - int search_flags = SEARCH_NOOF; - - if (ccline.cmdlen == 0) - goto cmdline_not_changed; - - if (firstc == ccline.cmdbuff[0]) - pat = last_search_pattern(); - else - pat = ccline.cmdbuff; - - save_last_search_pattern(); - cursor_off(); - out_flush(); - if (c == Ctrl_G) - { - t = match_end; - if (LT_POS(match_start, match_end)) - /* start searching at the end of the match - * not at the beginning of the next column */ - (void)decl(&t); - search_flags += SEARCH_COL; - } - else - t = match_start; - if (!p_hls) - search_flags += SEARCH_KEEP; - ++emsg_off; - i = searchit(curwin, curbuf, &t, - c == Ctrl_G ? FORWARD : BACKWARD, - pat, count, search_flags, - RE_SEARCH, 0, NULL, NULL); - --emsg_off; - if (i) - { - search_start = match_start; - match_end = t; - match_start = t; - if (c == Ctrl_T && firstc == '/') - { - /* move just before the current match, so that - * when nv_search finishes the cursor will be - * put back on the match */ - search_start = t; - (void)decl(&search_start); - } - else if (c == Ctrl_G && firstc == '?') - { - /* move just after the current match, so that - * when nv_search finishes the cursor will be - * put back on the match */ - search_start = t; - (void)incl(&search_start); - } - if (LT_POS(t, search_start) && c == Ctrl_G) - { - /* wrap around */ - search_start = t; - if (firstc == '?') - (void)incl(&search_start); - else - (void)decl(&search_start); - } - - set_search_match(&match_end); - curwin->w_cursor = match_start; - changed_cline_bef_curs(); - update_topline(); - validate_cursor(); - highlight_match = TRUE; - save_viewstate(&old_viewstate); - update_screen(NOT_VALID); - redrawcmdline(); - } - else - vim_beep(BO_ERROR); - restore_last_search_pattern(); + if (may_adjust_incsearch_highlighting( + firstc, count, &is_state, c) == FAIL) goto cmdline_not_changed; - } break; #endif @@ -1951,7 +2156,7 @@ getcmdline( */ cmdline_not_changed: #ifdef FEAT_SEARCH_EXTRA - if (!incsearch_postponed) + if (!is_state.incsearch_postponed) continue; #endif @@ -1960,115 +2165,7 @@ cmdline_changed: trigger_cmd_autocmd(cmdline_type, EVENT_CMDLINECHANGED); #ifdef FEAT_SEARCH_EXTRA - /* - * 'incsearch' highlighting. - */ - if (p_is && !cmd_silent && (firstc == '/' || firstc == '?')) - { - pos_T end_pos; -#ifdef FEAT_RELTIME - proftime_T tm; -#endif - - /* if there is a character waiting, search and redraw later */ - if (char_avail()) - { - incsearch_postponed = TRUE; - continue; - } - incsearch_postponed = FALSE; - curwin->w_cursor = search_start; /* start at old position */ - save_last_search_pattern(); - - /* If there is no command line, don't do anything */ - if (ccline.cmdlen == 0) - { - i = 0; - set_no_hlsearch(TRUE); /* turn off previous highlight */ - redraw_all_later(SOME_VALID); - } - else - { - int search_flags = SEARCH_OPT + SEARCH_NOOF + SEARCH_PEEK; - cursor_off(); /* so the user knows we're busy */ - out_flush(); - ++emsg_off; /* So it doesn't beep if bad expr */ -#ifdef FEAT_RELTIME - /* Set the time limit to half a second. */ - profile_setlimit(500L, &tm); -#endif - if (!p_hls) - search_flags += SEARCH_KEEP; - i = do_search(NULL, firstc, ccline.cmdbuff, count, - search_flags, -#ifdef FEAT_RELTIME - &tm, NULL -#else - NULL, NULL -#endif - ); - --emsg_off; - /* if interrupted while searching, behave like it failed */ - if (got_int) - { - (void)vpeekc(); /* remove from input stream */ - got_int = FALSE; /* don't abandon the command line */ - i = 0; - } - else if (char_avail()) - /* cancelled searching because a char was typed */ - incsearch_postponed = TRUE; - } - if (i != 0) - highlight_match = TRUE; /* highlight position */ - else - highlight_match = FALSE; /* remove highlight */ - - /* first restore the old curwin values, so the screen is - * positioned in the same way as the actual search command */ - restore_viewstate(&old_viewstate); - changed_cline_bef_curs(); - update_topline(); - - if (i != 0) - { - pos_T save_pos = curwin->w_cursor; - - match_start = curwin->w_cursor; - set_search_match(&curwin->w_cursor); - validate_cursor(); - end_pos = curwin->w_cursor; - match_end = end_pos; - curwin->w_cursor = save_pos; - } - else - end_pos = curwin->w_cursor; /* shutup gcc 4 */ - - /* Disable 'hlsearch' highlighting if the pattern matches - * everything. Avoids a flash when typing "foo\|". */ - if (empty_pattern(ccline.cmdbuff)) - set_no_hlsearch(TRUE); - - validate_cursor(); - /* May redraw the status line to show the cursor position. */ - if (p_ru && curwin->w_status_height > 0) - curwin->w_redr_status = TRUE; - - save_cmdline(&save_ccline); - update_screen(SOME_VALID); - restore_cmdline(&save_ccline); - restore_last_search_pattern(); - - /* Leave it at the end to make CTRL-R CTRL-W work. */ - if (i != 0) - curwin->w_cursor = end_pos; - - msg_starthere(); - redrawcmdline(); - did_incsearch = TRUE; - } -#else /* FEAT_SEARCH_EXTRA */ - ; + may_do_incsearch_highlighting(firstc, count, &is_state); #endif #ifdef FEAT_RIGHTLEFT @@ -2100,25 +2197,7 @@ returncmd: ccline.xpc = NULL; #ifdef FEAT_SEARCH_EXTRA - if (did_incsearch) - { - if (gotesc) - curwin->w_cursor = save_cursor; - else - { - if (!EQUAL_POS(save_cursor, search_start)) - { - /* put the '" mark at the original position */ - curwin->w_cursor = save_cursor; - setpcmark(); - } - curwin->w_cursor = search_start; - } - restore_viewstate(&old_viewstate); - highlight_match = FALSE; - validate_cursor(); /* needed for TAB */ - redraw_all_later(SOME_VALID); - } + finish_incsearch_highlighting(gotesc, &is_state); #endif if (ccline.cmdbuff != NULL) @@ -7239,21 +7318,3 @@ script_get(exarg_T *eap, char_u *cmd) return (char_u *)ga.ga_data; } - -#ifdef FEAT_SEARCH_EXTRA - static void -set_search_match(pos_T *t) -{ - /* - * First move cursor to end of match, then to the start. This - * moves the whole match onto the screen when 'nowrap' is set. - */ - t->lnum += search_match_lines; - t->col = search_match_endcol; - if (t->lnum > curbuf->b_ml.ml_line_count) - { - t->lnum = curbuf->b_ml.ml_line_count; - coladvance((colnr_T)MAXCOL); - } -} -#endif diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -795,6 +795,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 265, +/**/ 264, /**/ 263,