summaryrefslogtreecommitdiffstats
path: root/src/ex_getln.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2018-08-10 22:07:32 +0200
committerBram Moolenaar <Bram@vim.org>2018-08-10 22:07:32 +0200
commit0ee81cb63876e6ec1b2a6e0125295b43f1c63c7d (patch)
tree806f36b2c61a11cbbed59e09dfb23978d9ca39ca /src/ex_getln.c
parentefe03738f69b1f63ea30226765db949539ee15f0 (diff)
patch 8.1.0265: the getcmdline() function is way too bigv8.1.0265
Problem: The getcmdline() function is way too big. Solution: Factor out the incremental search highlighting.
Diffstat (limited to 'src/ex_getln.c')
-rw-r--r--src/ex_getln.c625
1 files changed, 343 insertions, 282 deletions
diff --git a/src/ex_getln.c b/src/ex_getln.c
index 54b37961f5..75984806a4 100644
--- a/src/ex_getln.c
+++ b/src/ex_getln.c
@@ -141,9 +141,6 @@ _RTLENTRYF
#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 <C-C> 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 <C-C> 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