To: vim_dev@googlegroups.com Subject: Patch 8.1.0265 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.1.0265 Problem: The getcmdline() function is way too big. Solution: Factor out the incremental search highlighting. Files: src/ex_getln.c *** ../vim-8.1.0264/src/ex_getln.c 2018-08-01 19:05:59.286223185 +0200 --- src/ex_getln.c 2018-08-10 22:05:38.646652603 +0200 *************** *** 141,149 **** #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 --- 141,146 ---- *************** *** 185,193 **** n -= 2; return n == 0 || (n >= 2 && p[n - 2] == '\\' && p[n - 1] == '|'); } - #endif ! #ifdef FEAT_SEARCH_EXTRA typedef struct { colnr_T vs_curswant; colnr_T vs_leftcol; --- 182,189 ---- n -= 2; return n == 0 || (n >= 2 && p[n - 2] == '\\' && p[n - 1] == '|'); } ! // Struct to store the viewstate during 'incsearch' highlighting. typedef struct { colnr_T vs_curswant; colnr_T vs_leftcol; *************** *** 224,229 **** --- 220,553 ---- 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,275 **** 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; #endif int did_wild_list = FALSE; /* did wild_list() recently */ int wim_index = 0; /* index in wim_flags[] */ --- 586,592 ---- int histype; /* history type to be used */ #endif #ifdef FEAT_SEARCH_EXTRA ! incsearch_state_T is_state; #endif int did_wild_list = FALSE; /* did wild_list() recently */ int wim_index = 0; /* index in wim_flags[] */ *************** *** 287,293 **** #endif expand_T xpc; long *b_im_ptr = NULL; ! #if defined(FEAT_WILDMENU) || defined(FEAT_EVAL) || defined(FEAT_SEARCH_EXTRA) /* 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". */ --- 604,610 ---- #endif expand_T xpc; long *b_im_ptr = NULL; ! #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,320 **** #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); #endif /* --- 626,634 ---- #endif ccline.overstrike = FALSE; /* always start in insert mode */ + #ifdef FEAT_SEARCH_EXTRA ! init_incsearch_state(&is_state); #endif /* *************** *** 1089,1098 **** #ifdef FEAT_SEARCH_EXTRA if (ccline.cmdlen == 0) { ! search_start = save_cursor; /* save view settings, so that the screen * won't be restored at the wrong position */ ! old_viewstate = init_viewstate; } #endif redrawcmd(); --- 1403,1412 ---- #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(); *************** *** 1121,1127 **** } #ifdef FEAT_SEARCH_EXTRA if (ccline.cmdlen == 0) ! search_start = save_cursor; #endif redraw_cmdline = TRUE; goto returncmd; /* back to cmd mode */ --- 1435,1441 ---- } #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 */ *************** *** 1208,1214 **** ccline.cmdbuff[ccline.cmdlen] = NUL; #ifdef FEAT_SEARCH_EXTRA if (ccline.cmdlen == 0) ! search_start = save_cursor; #endif redrawcmd(); goto cmdline_changed; --- 1522,1528 ---- ccline.cmdbuff[ccline.cmdlen] = NUL; #ifdef FEAT_SEARCH_EXTRA if (ccline.cmdlen == 0) ! is_state.search_start = is_state.save_cursor; #endif redrawcmd(); goto cmdline_changed; *************** *** 1545,1582 **** 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; ! } ! } ! } goto cmdline_not_changed; - } #endif /* completion: longest common part */ --- 1859,1866 ---- case Ctrl_L: #ifdef FEAT_SEARCH_EXTRA ! if (may_add_char_to_search(firstc, &c, &is_state) == OK) goto cmdline_not_changed; #endif /* completion: longest common part */ *************** *** 1742,1829 **** #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(); goto cmdline_not_changed; - } break; #endif --- 2026,2034 ---- #ifdef FEAT_SEARCH_EXTRA case Ctrl_G: /* next match */ case Ctrl_T: /* previous match */ ! if (may_adjust_incsearch_highlighting( ! firstc, count, &is_state, c) == FAIL) goto cmdline_not_changed; break; #endif *************** *** 1951,1957 **** */ cmdline_not_changed: #ifdef FEAT_SEARCH_EXTRA ! if (!incsearch_postponed) continue; #endif --- 2156,2162 ---- */ cmdline_not_changed: #ifdef FEAT_SEARCH_EXTRA ! if (!is_state.incsearch_postponed) continue; #endif *************** *** 1960,2074 **** 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 */ ! ; #endif #ifdef FEAT_RIGHTLEFT --- 2165,2171 ---- trigger_cmd_autocmd(cmdline_type, EVENT_CMDLINECHANGED); #ifdef FEAT_SEARCH_EXTRA ! may_do_incsearch_highlighting(firstc, count, &is_state); #endif #ifdef FEAT_RIGHTLEFT *************** *** 2100,2124 **** 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); ! } #endif if (ccline.cmdbuff != NULL) --- 2197,2203 ---- ccline.xpc = NULL; #ifdef FEAT_SEARCH_EXTRA ! finish_incsearch_highlighting(gotesc, &is_state); #endif if (ccline.cmdbuff != NULL) *************** *** 7239,7259 **** 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 --- 7318,7320 ---- *** ../vim-8.1.0264/src/version.c 2018-08-09 22:26:34.259501130 +0200 --- src/version.c 2018-08-10 22:07:22.817944576 +0200 *************** *** 796,797 **** --- 796,799 ---- { /* Add new patch number below this line */ + /**/ + 265, /**/ -- Sorry, no fortune today. /// 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 ///