diff options
Diffstat (limited to 'src/search.c')
-rw-r--r-- | src/search.c | 345 |
1 files changed, 251 insertions, 94 deletions
diff --git a/src/search.c b/src/search.c index 166ef4a..0b39d90 100644 --- a/src/search.c +++ b/src/search.c @@ -17,8 +17,8 @@ static void set_vv_searchforward(void); static int first_submatch(regmmatch_T *rp); #endif #ifdef FEAT_FIND_ID -static void show_pat_in_path(char_u *, int, - int, int, FILE *, linenr_T *, long); +static char_u *get_line_and_copy(linenr_T lnum, char_u *buf); +static void show_pat_in_path(char_u *, int, int, int, FILE *, linenr_T *, long); #endif typedef struct searchstat @@ -32,8 +32,27 @@ typedef struct searchstat int last_maxcount; // the max count of the last search } searchstat_T; -static void cmdline_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, int show_top_bot_msg, char_u *msgbuf, int recompute, int maxcount, long timeout); +#ifdef FEAT_SEARCH_EXTRA +static void save_incsearch_state(void); +static void restore_incsearch_state(void); +#endif +static int check_prevcol(char_u *linep, int col, int ch, int *prevcol); +static int find_rawstring_end(char_u *linep, pos_T *startpos, pos_T *endpos); +static void find_mps_values(int *initc, int *findc, int *backwards, int switchit); +static int is_zero_width(char_u *pattern, size_t patternlen, int move, pos_T *cur, int direction); +static void cmdline_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, int show_top_bot_msg, char_u *msgbuf, size_t msgbuflen, int recompute, int maxcount, long timeout); static void update_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, searchstat_T *stat, int recompute, int maxcount, long timeout); +static int fuzzy_match_compute_score(char_u *str, int strSz, int_u *matches, int numMatches); +static int fuzzy_match_recursive(char_u *fuzpat, char_u *str, int_u strIdx, int *outScore, char_u *strBegin, int strLen, int_u *srcMatches, int_u *matches, int maxMatches, int nextMatch, int *recursionCount); +#if defined(FEAT_EVAL) || defined(FEAT_PROTO) +static int fuzzy_match_item_compare(const void *s1, const void *s2); +static void fuzzy_match_in_list(list_T *l, char_u *str, int matchseq, char_u *key, callback_T *item_cb, int retmatchpos, list_T *fmatchlist, long max_matches); +static void do_fuzzymatch(typval_T *argvars, typval_T *rettv, int retmatchpos); +#endif +static int fuzzy_match_str_compare(const void *s1, const void *s2); +static void fuzzy_match_str_sort(fuzmatch_str_T *fm, int sz); +static int fuzzy_match_func_compare(const void *s1, const void *s2); +static void fuzzy_match_func_sort(fuzmatch_str_T *fm, int sz); #define SEARCH_STAT_DEF_TIMEOUT 40L #define SEARCH_STAT_DEF_MAX_COUNT 99 @@ -69,8 +88,8 @@ static void update_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, searchst */ static spat_T spats[2] = { - {NULL, TRUE, FALSE, {'/', 0, 0, 0L}}, // last used search pat - {NULL, TRUE, FALSE, {'/', 0, 0, 0L}} // last used substitute pat + {NULL, 0, TRUE, FALSE, {'/', 0, 0, 0L}}, // last used search pat + {NULL, 0, TRUE, FALSE, {'/', 0, 0, 0L}} // last used substitute pat }; static int last_idx = 0; // index in spats[] for RE_LAST @@ -82,8 +101,9 @@ static char_u lastc_bytes[MB_MAXBYTES + 1]; static int lastc_bytelen = 1; // >1 for multi-byte char // copy of spats[], for keeping the search patterns while executing autocmds -static spat_T saved_spats[2]; +static spat_T saved_spats[ARRAY_LENGTH(spats)]; static char_u *saved_mr_pattern = NULL; +static size_t saved_mr_patternlen = 0; # ifdef FEAT_SEARCH_EXTRA static int saved_spats_last_idx = 0; static int saved_spats_no_hlsearch = 0; @@ -91,6 +111,7 @@ static int saved_spats_no_hlsearch = 0; // allocated copy of pattern used by search_regcomp() static char_u *mr_pattern = NULL; +static size_t mr_patternlen = 0; #ifdef FEAT_FIND_ID /* @@ -123,6 +144,7 @@ typedef struct SearchedFile int search_regcomp( char_u *pat, + size_t patlen, char_u **used_pat, int pat_save, int pat_use, @@ -130,7 +152,6 @@ search_regcomp( regmmatch_T *regmatch) // return: pattern and ignore-case flag { int magic; - int i; rc_did_emsg = FALSE; magic = magic_isset(); @@ -140,6 +161,8 @@ search_regcomp( */ if (pat == NULL || *pat == NUL) { + int i; + if (pat_use == RE_LAST) i = last_idx; else @@ -154,11 +177,12 @@ search_regcomp( return FAIL; } pat = spats[i].pat; + patlen = spats[i].patlen; magic = spats[i].magic; no_smartcase = spats[i].no_scs; } else if (options & SEARCH_HIS) // put new pattern in history - add_to_history(HIST_SEARCH, pat, TRUE, NUL); + add_to_history(HIST_SEARCH, pat, patlen, TRUE, NUL); if (used_pat) *used_pat = pat; @@ -169,7 +193,11 @@ search_regcomp( mr_pattern = reverse_text(pat); else #endif - mr_pattern = vim_strsave(pat); + mr_pattern = vim_strnsave(pat, patlen); + if (mr_pattern == NULL) + mr_patternlen = 0; + else + mr_patternlen = patlen; /* * Save the currently used pattern in the appropriate place, @@ -180,10 +208,10 @@ search_regcomp( { // search or global command if (pat_save == RE_SEARCH || pat_save == RE_BOTH) - save_re_pat(RE_SEARCH, pat, magic); + save_re_pat(RE_SEARCH, pat, patlen, magic); // substitute or global command if (pat_save == RE_SUBST || pat_save == RE_BOTH) - save_re_pat(RE_SUBST, pat, magic); + save_re_pat(RE_SUBST, pat, patlen, magic); } regmatch->rmm_ic = ignorecase(pat); @@ -204,13 +232,17 @@ get_search_pat(void) } void -save_re_pat(int idx, char_u *pat, int magic) +save_re_pat(int idx, char_u *pat, size_t patlen, int magic) { if (spats[idx].pat == pat) return; vim_free(spats[idx].pat); - spats[idx].pat = vim_strsave(pat); + spats[idx].pat = vim_strnsave(pat, patlen); + if (spats[idx].pat == NULL) + spats[idx].patlen = 0; + else + spats[idx].patlen = patlen; spats[idx].magic = magic; spats[idx].no_scs = no_smartcase; last_idx = idx; @@ -231,19 +263,31 @@ static int save_level = 0; void save_search_patterns(void) { + int i; + if (save_level++ != 0) return; - saved_spats[0] = spats[0]; - if (spats[0].pat != NULL) - saved_spats[0].pat = vim_strsave(spats[0].pat); - saved_spats[1] = spats[1]; - if (spats[1].pat != NULL) - saved_spats[1].pat = vim_strsave(spats[1].pat); + for (i = 0; i < (int)ARRAY_LENGTH(spats); ++i) + { + saved_spats[i] = spats[i]; + if (spats[i].pat != NULL) + { + saved_spats[i].pat = vim_strnsave(spats[i].pat, spats[i].patlen); + if (saved_spats[i].pat == NULL) + saved_spats[i].patlen = 0; + else + saved_spats[i].patlen = spats[i].patlen; + } + } if (mr_pattern == NULL) saved_mr_pattern = NULL; else - saved_mr_pattern = vim_strsave(mr_pattern); + saved_mr_pattern = vim_strnsave(mr_pattern, mr_patternlen); + if (saved_mr_pattern == NULL) + saved_mr_patternlen = 0; + else + saved_mr_patternlen = mr_patternlen; #ifdef FEAT_SEARCH_EXTRA saved_spats_last_idx = last_idx; saved_spats_no_hlsearch = no_hlsearch; @@ -253,18 +297,22 @@ save_search_patterns(void) void restore_search_patterns(void) { + int i; + if (--save_level != 0) return; - vim_free(spats[0].pat); - spats[0] = saved_spats[0]; + for (i = 0; i < (int)ARRAY_LENGTH(spats); ++i) + { + vim_free(spats[i].pat); + spats[i] = saved_spats[i]; + } #if defined(FEAT_EVAL) set_vv_searchforward(); #endif - vim_free(spats[1].pat); - spats[1] = saved_spats[1]; vim_free(mr_pattern); mr_pattern = saved_mr_pattern; + mr_patternlen = saved_mr_patternlen; #ifdef FEAT_SEARCH_EXTRA last_idx = saved_spats_last_idx; set_no_hlsearch(saved_spats_no_hlsearch); @@ -275,9 +323,15 @@ restore_search_patterns(void) void free_search_patterns(void) { - vim_free(spats[0].pat); - vim_free(spats[1].pat); + int i; + + for (i = 0; i < (int)ARRAY_LENGTH(spats); ++i) + { + VIM_CLEAR(spats[i].pat); + spats[i].patlen = 0; + } VIM_CLEAR(mr_pattern); + mr_patternlen = 0; } #endif @@ -308,7 +362,13 @@ save_last_search_pattern(void) saved_last_search_spat = spats[RE_SEARCH]; if (spats[RE_SEARCH].pat != NULL) - saved_last_search_spat.pat = vim_strsave(spats[RE_SEARCH].pat); + { + saved_last_search_spat.pat = vim_strnsave(spats[RE_SEARCH].pat, spats[RE_SEARCH].patlen); + if (saved_last_search_spat.pat == NULL) + saved_last_search_spat.patlen = 0; + else + saved_last_search_spat.patlen = spats[RE_SEARCH].patlen; + } saved_last_idx = last_idx; saved_no_hlsearch = no_hlsearch; } @@ -328,6 +388,7 @@ restore_last_search_pattern(void) vim_free(spats[RE_SEARCH].pat); spats[RE_SEARCH] = saved_last_search_spat; saved_last_search_spat.pat = NULL; + saved_last_search_spat.patlen = 0; # if defined(FEAT_EVAL) set_vv_searchforward(); # endif @@ -513,7 +574,12 @@ set_last_search_pat( if (*s == NUL) spats[idx].pat = NULL; else - spats[idx].pat = vim_strsave(s); + { + spats[idx].patlen = STRLEN(s); + spats[idx].pat = vim_strnsave(s, spats[idx].patlen); + } + if (spats[idx].pat == NULL) + spats[idx].patlen = 0; spats[idx].magic = magic; spats[idx].no_scs = FALSE; spats[idx].off.dir = '/'; @@ -532,7 +598,11 @@ set_last_search_pat( if (spats[idx].pat == NULL) saved_spats[idx].pat = NULL; else - saved_spats[idx].pat = vim_strsave(spats[idx].pat); + saved_spats[idx].pat = vim_strnsave(spats[idx].pat, spats[idx].patlen); + if (saved_spats[idx].pat == NULL) + saved_spats[idx].patlen = 0; + else + saved_spats[idx].patlen = spats[idx].patlen; # ifdef FEAT_SEARCH_EXTRA saved_spats_last_idx = last_idx; # endif @@ -560,7 +630,7 @@ last_pat_prog(regmmatch_T *regmatch) return; } ++emsg_off; // So it doesn't beep if bad expr - (void)search_regcomp((char_u *)"", NULL, 0, last_idx, SEARCH_KEEP, regmatch); + (void)search_regcomp((char_u *)"", 0, NULL, 0, last_idx, SEARCH_KEEP, regmatch); --emsg_off; } #endif @@ -594,6 +664,7 @@ searchit( pos_T *end_pos, // set to end of the match, unless NULL int dir, char_u *pat, + size_t patlen, long count, int options, int pat_use, // which pattern to use when "pat" is empty @@ -623,8 +694,9 @@ searchit( linenr_T stop_lnum = 0; // stop after this line number when != 0 int unused_timeout_flag = FALSE; int *timed_out = &unused_timeout_flag; // set when timed out. + int search_from_match_end; // vi-compatible search? - if (search_regcomp(pat, NULL, RE_SEARCH, pat_use, + if (search_regcomp(pat, patlen, NULL, RE_SEARCH, pat_use, (options & (SEARCH_HIS + SEARCH_KEEP)), ®match) == FAIL) { if ((options & SEARCH_MSG) && !rc_did_emsg) @@ -632,6 +704,8 @@ searchit( return FAIL; } + search_from_match_end = vim_strchr(p_cpo, CPO_SEARCH) != NULL; + if (extra_arg != NULL) { stop_lnum = extra_arg->sa_stop_lnum; @@ -778,7 +852,7 @@ searchit( * of the match, otherwise continue one position * forward. */ - if (vim_strchr(p_cpo, CPO_SEARCH) != NULL) + if (search_from_match_end) { if (nmatched > 1) { @@ -890,7 +964,7 @@ searchit( * of the match, otherwise continue one position * forward. */ - if (vim_strchr(p_cpo, CPO_SEARCH) != NULL) + if (search_from_match_end) { if (nmatched > 1) break; @@ -1173,12 +1247,14 @@ do_search( int search_delim, // the delimiter for the search, e.g. '%' in // s%regex%replacement% char_u *pat, + size_t patlen, long count, int options, searchit_arg_T *sia) // optional arguments or NULL { pos_T pos; // position of the last match char_u *searchstr; + size_t searchstrlen; soffset_T old_off; int retval; // Return value char_u *p; @@ -1186,10 +1262,13 @@ do_search( char_u *dircp; char_u *strcopy = NULL; char_u *ps; + int show_search_stats; char_u *msgbuf = NULL; - size_t len; + size_t msgbuflen = 0; int has_offset = FALSE; + searchcmdlen = 0; + /* * A line offset is not remembered, this is vi compatible. */ @@ -1267,24 +1346,28 @@ do_search( int show_top_bot_msg = FALSE; searchstr = pat; + searchstrlen = patlen; + dircp = NULL; // use previous pattern if (pat == NULL || *pat == NUL || *pat == search_delim) { if (spats[RE_SEARCH].pat == NULL) // no previous pattern { - searchstr = spats[RE_SUBST].pat; - if (searchstr == NULL) + if (spats[RE_SUBST].pat == NULL) { emsg(_(e_no_previous_regular_expression)); retval = 0; goto end_do_search; } + searchstr = spats[RE_SUBST].pat; + searchstrlen = spats[RE_SUBST].patlen; } else { // make search_regcomp() use spats[RE_SEARCH].pat searchstr = (char_u *)""; + searchstrlen = 0; } } @@ -1299,13 +1382,17 @@ do_search( &strcopy, NULL, NULL); if (strcopy != ps) { + size_t len = STRLEN(strcopy); // made a copy of "pat" to change "\?" to "?" - searchcmdlen += (int)(STRLEN(pat) - STRLEN(strcopy)); + searchcmdlen += (int)(patlen - len); pat = strcopy; + patlen = len; searchstr = strcopy; + searchstrlen = len; } if (*p == search_delim) { + searchstrlen = p - pat; dircp = p; // remember where we put the NUL *p++ = NUL; } @@ -1344,16 +1431,19 @@ do_search( // compute length of search command for get_address() searchcmdlen += (int)(p - pat); + patlen -= p - pat; pat = p; // put pat after search command } + show_search_stats = FALSE; if ((options & SEARCH_ECHO) && messaging() && !msg_silent && (!cmd_silent || !shortmess(SHM_SEARCHCOUNT))) { - char_u *trunc; char_u off_buf[40]; size_t off_len = 0; + size_t plen; + size_t msgbufsize; // Compute msg_row early. msg_start(); @@ -1362,24 +1452,28 @@ do_search( if (!cmd_silent && (spats[0].off.line || spats[0].off.end || spats[0].off.off)) { - p = off_buf; - *p++ = dirc; + off_buf[off_len++] = dirc; if (spats[0].off.end) - *p++ = 'e'; + off_buf[off_len++] = 'e'; else if (!spats[0].off.line) - *p++ = 's'; + off_buf[off_len++] = 's'; if (spats[0].off.off > 0 || spats[0].off.line) - *p++ = '+'; - *p = NUL; + off_buf[off_len++] = '+'; + off_buf[off_len] = NUL; if (spats[0].off.off != 0 || spats[0].off.line) - sprintf((char *)p, "%ld", spats[0].off.off); - off_len = STRLEN(off_buf); + off_len += vim_snprintf((char *)off_buf + off_len, sizeof(off_buf) - off_len, "%ld", spats[0].off.off); } if (*searchstr == NUL) + { p = spats[0].pat; + plen = spats[0].patlen; + } else + { p = searchstr; + plen = searchstrlen; + } if (!shortmess(SHM_SEARCHCOUNT) || cmd_silent) { @@ -1389,45 +1483,53 @@ do_search( // msg_strtrunc() will shorten in the middle. if (msg_scrolled != 0 && !cmd_silent) // Use all the columns. - len = (int)(Rows - msg_row) * Columns - 1; + msgbufsize = (int)(Rows - msg_row) * Columns - 1; else // Use up to 'showcmd' column. - len = (int)(Rows - msg_row - 1) * Columns + sc_col - 1; - if (len < STRLEN(p) + off_len + SEARCH_STAT_BUF_LEN + 3) - len = STRLEN(p) + off_len + SEARCH_STAT_BUF_LEN + 3; + msgbufsize = (int)(Rows - msg_row - 1) * Columns + sc_col - 1; + if (msgbufsize < plen + off_len + SEARCH_STAT_BUF_LEN + 3) + msgbufsize = plen + off_len + SEARCH_STAT_BUF_LEN + 3; } else // Reserve enough space for the search pattern + offset. - len = STRLEN(p) + off_len + 3; + msgbufsize = plen + off_len + 3; vim_free(msgbuf); - msgbuf = alloc(len); - if (msgbuf != NULL) + msgbuf = alloc(msgbufsize); + if (msgbuf == NULL) { - vim_memset(msgbuf, ' ', len); - msgbuf[len - 1] = NUL; + msgbuflen = 0; + } + else + { + vim_memset(msgbuf, ' ', msgbufsize); + msgbuflen = msgbufsize - 1; + msgbuf[msgbuflen] = NUL; // do not fill the msgbuf buffer, if cmd_silent is set, leave it // empty for the search_stat feature. if (!cmd_silent) { + char_u *trunc; + msgbuf[0] = dirc; if (enc_utf8 && utf_iscomposing(utf_ptr2char(p))) { // Use a space to draw the composing char on. msgbuf[1] = ' '; - mch_memmove(msgbuf + 2, p, STRLEN(p)); + mch_memmove(msgbuf + 2, p, plen); } else - mch_memmove(msgbuf + 1, p, STRLEN(p)); + mch_memmove(msgbuf + 1, p, plen); if (off_len > 0) - mch_memmove(msgbuf + STRLEN(p) + 1, off_buf, off_len); + mch_memmove(msgbuf + plen + 1, off_buf, off_len); trunc = msg_strtrunc(msgbuf, TRUE); if (trunc != NULL) { vim_free(msgbuf); msgbuf = trunc; + msgbuflen = STRLEN(msgbuf); } #ifdef FEAT_RIGHTLEFT @@ -1448,7 +1550,7 @@ do_search( // move reversed text to beginning of buffer while (*r != NUL && *r == ' ') r++; - pat_len = msgbuf + STRLEN(msgbuf) - r; + pat_len = msgbuf + msgbuflen - r; mch_memmove(msgbuf, r, pat_len); // overwrite old text if ((size_t)(r - msgbuf) >= pat_len) @@ -1466,7 +1568,10 @@ do_search( out_flush(); msg_nowait = TRUE; // don't wait for this message } - } + + if (!shortmess(SHM_SEARCHCOUNT)) + show_search_stats = TRUE; + } // msgbuf != NULL } /* @@ -1507,7 +1612,7 @@ do_search( */ c = searchit(curwin, curbuf, &pos, NULL, dirc == '/' ? FORWARD : BACKWARD, - searchstr, count, spats[0].off.end + (options & + searchstr, searchstrlen, count, spats[0].off.end + (options & (SEARCH_KEEP + SEARCH_PEEK + SEARCH_HIS + SEARCH_MSG + SEARCH_START + ((pat != NULL && *pat == ';') ? 0 : SEARCH_NOOF))), @@ -1574,14 +1679,9 @@ do_search( } // Show [1/15] if 'S' is not in 'shortmess'. - if ((options & SEARCH_ECHO) - && messaging() - && !msg_silent - && c != FAIL - && !shortmess(SHM_SEARCHCOUNT) - && msgbuf != NULL) + if (show_search_stats) cmdline_search_stat(dirc, &pos, &curwin->w_cursor, - show_top_bot_msg, msgbuf, + show_top_bot_msg, msgbuf, msgbuflen, (count != 1 || has_offset #ifdef FEAT_FOLDING || (!(fdo_flags & FDO_SEARCH) @@ -1612,6 +1712,7 @@ do_search( goto end_do_search; } ++pat; + --patlen; } if (options & SEARCH_MARK) @@ -2825,7 +2926,7 @@ showmatch( * Returns TRUE, FALSE or -1 for failure. */ static int -is_zero_width(char_u *pattern, int move, pos_T *cur, int direction) +is_zero_width(char_u *pattern, size_t patternlen, int move, pos_T *cur, int direction) { regmmatch_T regmatch; int nmatched = 0; @@ -2835,9 +2936,12 @@ is_zero_width(char_u *pattern, int move, pos_T *cur, int direction) int flag = 0; if (pattern == NULL) + { pattern = spats[last_idx].pat; + patternlen = spats[last_idx].patlen; + } - if (search_regcomp(pattern, NULL, RE_SEARCH, RE_SEARCH, + if (search_regcomp(pattern, patternlen, NULL, RE_SEARCH, RE_SEARCH, SEARCH_KEEP, ®match) == FAIL) return -1; @@ -2855,7 +2959,7 @@ is_zero_width(char_u *pattern, int move, pos_T *cur, int direction) flag = SEARCH_START; } - if (searchit(curwin, curbuf, &pos, NULL, direction, pattern, 1, + if (searchit(curwin, curbuf, &pos, NULL, direction, pattern, patternlen, 1, SEARCH_KEEP + flag, RE_SEARCH, NULL) != FAIL) { // Zero-width pattern should match somewhere, then we can check if @@ -2925,8 +3029,8 @@ current_search( } // Is the pattern is zero-width?, this time, don't care about the direction - zero_width = is_zero_width(spats[last_idx].pat, TRUE, &curwin->w_cursor, - FORWARD); + zero_width = is_zero_width(spats[last_idx].pat, spats[last_idx].patlen, + TRUE, &curwin->w_cursor, FORWARD); if (zero_width == -1) return FAIL; // pattern not found @@ -2957,7 +3061,7 @@ current_search( result = searchit(curwin, curbuf, &pos, &end_pos, (dir ? FORWARD : BACKWARD), - spats[last_idx].pat, (long) (i ? count : 1), + spats[last_idx].pat, spats[last_idx].patlen, (long) (i ? count : 1), SEARCH_KEEP | flags, RE_SEARCH, NULL); p_ws = old_p_ws; @@ -3061,6 +3165,7 @@ cmdline_search_stat( pos_T *cursor_pos, int show_top_bot_msg, char_u *msgbuf, + size_t msgbuflen, int recompute, int maxcount, long timeout) @@ -3079,34 +3184,33 @@ cmdline_search_stat( if (curwin->w_p_rl && *curwin->w_p_rlc == 's') { if (stat.incomplete == 1) - vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]"); + len = vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]"); else if (stat.cnt > maxcount && stat.cur > maxcount) - vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>%d/>%d]", + len = vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>%d/>%d]", maxcount, maxcount); else if (stat.cnt > maxcount) - vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>%d/%d]", + len = vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>%d/%d]", maxcount, stat.cur); else - vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]", + len = vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]", stat.cnt, stat.cur); } else #endif { if (stat.incomplete == 1) - vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]"); + len = vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]"); else if (stat.cnt > maxcount && stat.cur > maxcount) - vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>%d/>%d]", + len = vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[>%d/>%d]", maxcount, maxcount); else if (stat.cnt > maxcount) - vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/>%d]", + len = vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/>%d]", stat.cur, maxcount); else - vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]", + len = vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]", stat.cur, stat.cnt); } - len = STRLEN(t); if (show_top_bot_msg && len + 2 < SEARCH_STAT_BUF_LEN) { mch_memmove(t + 2, t, len); @@ -3115,10 +3219,9 @@ cmdline_search_stat( len += 2; } - size_t msgbuf_len = STRLEN(msgbuf); - if (len > msgbuf_len) - len = msgbuf_len; - mch_memmove(msgbuf + msgbuf_len - len, t, len); + if (len > msgbuflen) + len = msgbuflen; + mch_memmove(msgbuf + msgbuflen - len, t, len); if (dirc == '?' && stat.cur == maxcount + 1) stat.cur = -1; @@ -3214,7 +3317,7 @@ update_search_stat( profile_setlimit(timeout, &start); #endif while (!got_int && searchit(curwin, curbuf, &lastpos, &endpos, - FORWARD, NULL, 1, SEARCH_KEEP, RE_LAST, NULL) != FAIL) + FORWARD, NULL, 0, 1, SEARCH_KEEP, RE_LAST, NULL) != FAIL) { done_search = TRUE; #ifdef FEAT_RELTIME @@ -3342,7 +3445,7 @@ find_pattern_in_path( pat = alloc(len + 5); if (pat == NULL) goto fpip_end; - sprintf((char *)pat, whole ? "\\<%.*s\\>" : "%.*s", len, ptr); + vim_snprintf((char *)pat, len + 5, whole ? "\\<%.*s\\>" : "%.*s", len, ptr); // ignore case according to p_ic, p_scs and pat regmatch.rm_ic = ignorecase(pat); regmatch.regprog = vim_regcomp(pat, magic_isset() ? RE_MAGIC : 0); @@ -3361,8 +3464,7 @@ find_pattern_in_path( } if (type == FIND_DEFINE && (*curbuf->b_p_def != NUL || *p_def != NUL)) { - def_regmatch.regprog = vim_regcomp(*curbuf->b_p_def == NUL - ? p_def : curbuf->b_p_def, + def_regmatch.regprog = vim_regcomp(*curbuf->b_p_def == NUL ? p_def : curbuf->b_p_def, magic_isset() ? RE_MAGIC : 0); if (def_regmatch.regprog == NULL) goto fpip_end; @@ -3879,7 +3981,7 @@ exit_matched: && action == ACTION_EXPAND && !compl_status_sol() && *startp != NUL - && *(p = startp + mb_ptr2len(startp)) != NUL) + && *(startp + mb_ptr2len(startp)) != NUL) goto search_line; } line_breakcheck(); @@ -3976,6 +4078,7 @@ show_pat_in_path( long count) { char_u *p; + size_t linelen; if (did_show) msg_putchar('\n'); // cursor below last one @@ -3983,9 +4086,10 @@ show_pat_in_path( gotocmdline(TRUE); // cursor at status line if (got_int) // 'q' typed at "--more--" message return; + linelen = STRLEN(line); for (;;) { - p = line + STRLEN(line) - 1; + p = line + linelen - 1; if (fp != NULL) { // We used fgets(), so get rid of newline at end @@ -4015,6 +4119,7 @@ show_pat_in_path( { if (vim_fgets(line, LSIZE, fp)) // end of file break; + linelen = STRLEN(line); ++*lnum; } else @@ -4022,6 +4127,7 @@ show_pat_in_path( if (++*lnum > curbuf->b_ml.ml_line_count) break; line = ml_get(*lnum); + linelen = ml_get_len(*lnum); } msg_putchar('\n'); } @@ -4149,7 +4255,10 @@ f_searchcount(typval_T *argvars, typval_T *rettv) if (*pattern == NUL) goto the_end; vim_free(spats[last_idx].pat); - spats[last_idx].pat = vim_strsave(pattern); + spats[last_idx].patlen = STRLEN(pattern); + spats[last_idx].pat = vim_strnsave(pattern, spats[last_idx].patlen); + if (spats[last_idx].pat == NULL) + spats[last_idx].patlen = 0; } if (spats[last_idx].pat == NULL || *spats[last_idx].pat == NUL) goto the_end; // the previous pattern was never defined @@ -4983,6 +5092,54 @@ fuzzy_match_str(char_u *str, char_u *pat) } /* + * Fuzzy match the position of string 'pat' in string 'str'. + * Returns a dynamic array of matching positions. If there is no match, + * returns NULL. + */ + garray_T * +fuzzy_match_str_with_pos(char_u *str UNUSED, char_u *pat UNUSED) +{ +#ifdef FEAT_SEARCH_EXTRA + int score = 0; + garray_T *match_positions = NULL; + int_u matches[MAX_FUZZY_MATCHES]; + int j = 0; + + if (str == NULL || pat == NULL) + return NULL; + + match_positions = ALLOC_ONE(garray_T); + if (match_positions == NULL) + return NULL; + ga_init2(match_positions, sizeof(int_u), 10); + + if (!fuzzy_match(str, pat, FALSE, &score, matches, MAX_FUZZY_MATCHES) + || score == 0) + { + ga_clear(match_positions); + vim_free(match_positions); + return NULL; + } + + for (char_u *p = pat; *p != NUL; MB_PTR_ADV(p)) + { + if (!VIM_ISWHITE(PTR2CHAR(p))) + { + ga_grow(match_positions, 1); + ((int_u *)match_positions->ga_data)[match_positions->ga_len] = + matches[j]; + match_positions->ga_len++; + j++; + } + } + + return match_positions; +#else + return NULL; +#endif +} + +/* * Free an array of fuzzy string matches "fuzmatch[count]". */ void |