aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/search.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/search.c')
-rw-r--r--src/nvim/search.c486
1 files changed, 305 insertions, 181 deletions
diff --git a/src/nvim/search.c b/src/nvim/search.c
index 871d2f9a0a..eb5cc2e07f 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -133,7 +133,7 @@ typedef struct SearchedFile {
/// @param regmatch return: pattern and ignore-case flag
///
/// @return FAIL if failed, OK otherwise.
-int search_regcomp(char_u *pat, char_u **used_pat, int pat_save, int pat_use, int options,
+int search_regcomp(char *pat, char **used_pat, int pat_save, int pat_use, int options,
regmmatch_T *regmatch)
{
int magic;
@@ -158,11 +158,11 @@ int search_regcomp(char_u *pat, char_u **used_pat, int pat_save, int pat_use, in
rc_did_emsg = true;
return FAIL;
}
- pat = (char_u *)spats[i].pat;
+ pat = spats[i].pat;
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, (char *)pat, true, NUL);
+ add_to_history(HIST_SEARCH, pat, true, NUL);
}
if (used_pat) {
@@ -171,9 +171,9 @@ int search_regcomp(char_u *pat, char_u **used_pat, int pat_save, int pat_use, in
xfree(mr_pattern);
if (curwin->w_p_rl && *curwin->w_p_rlc == 's') {
- mr_pattern = reverse_text((char *)pat);
+ mr_pattern = reverse_text(pat);
} else {
- mr_pattern = xstrdup((char *)pat);
+ mr_pattern = xstrdup(pat);
}
// Save the currently used pattern in the appropriate place,
@@ -181,17 +181,17 @@ int search_regcomp(char_u *pat, char_u **used_pat, int pat_save, int pat_use, in
if (!(options & SEARCH_KEEP) && (cmdmod.cmod_flags & CMOD_KEEPPATTERNS) == 0) {
// search or global command
if (pat_save == RE_SEARCH || pat_save == RE_BOTH) {
- save_re_pat(RE_SEARCH, (char *)pat, magic);
+ save_re_pat(RE_SEARCH, pat, magic);
}
// substitute or global command
if (pat_save == RE_SUBST || pat_save == RE_BOTH) {
- save_re_pat(RE_SUBST, (char *)pat, magic);
+ save_re_pat(RE_SUBST, pat, magic);
}
}
- regmatch->rmm_ic = ignorecase((char *)pat);
+ regmatch->rmm_ic = ignorecase(pat);
regmatch->rmm_maxcol = 0;
- regmatch->regprog = vim_regcomp((char *)pat, magic ? RE_MAGIC : 0);
+ regmatch->regprog = vim_regcomp(pat, magic ? RE_MAGIC : 0);
if (regmatch->regprog == NULL) {
return FAIL;
}
@@ -206,20 +206,22 @@ char *get_search_pat(void)
void save_re_pat(int idx, char *pat, int magic)
{
- if (spats[idx].pat != pat) {
- free_spat(&spats[idx]);
- spats[idx].pat = xstrdup(pat);
- spats[idx].magic = magic;
- spats[idx].no_scs = no_smartcase;
- spats[idx].timestamp = os_time();
- spats[idx].additional_data = NULL;
- last_idx = idx;
- // If 'hlsearch' set and search pat changed: need redraw.
- if (p_hls) {
- redraw_all_later(UPD_SOME_VALID);
- }
- set_no_hlsearch(false);
+ if (spats[idx].pat == pat) {
+ return;
+ }
+
+ free_spat(&spats[idx]);
+ spats[idx].pat = xstrdup(pat);
+ spats[idx].magic = magic;
+ spats[idx].no_scs = no_smartcase;
+ spats[idx].timestamp = os_time();
+ spats[idx].additional_data = NULL;
+ last_idx = idx;
+ // If 'hlsearch' set and search pat changed: need redraw.
+ if (p_hls) {
+ redraw_all_later(UPD_SOME_VALID);
}
+ set_no_hlsearch(false);
}
// Save the search patterns, so they can be restored later.
@@ -228,38 +230,42 @@ static int save_level = 0;
void save_search_patterns(void)
{
- if (save_level++ == 0) {
- saved_spats[0] = spats[0];
- if (spats[0].pat != NULL) {
- saved_spats[0].pat = xstrdup(spats[0].pat);
- }
- saved_spats[1] = spats[1];
- if (spats[1].pat != NULL) {
- saved_spats[1].pat = xstrdup(spats[1].pat);
- }
- if (mr_pattern == NULL) {
- saved_mr_pattern = NULL;
- } else {
- saved_mr_pattern = xstrdup(mr_pattern);
- }
- saved_spats_last_idx = last_idx;
- saved_spats_no_hlsearch = no_hlsearch;
+ if (save_level++ != 0) {
+ return;
+ }
+
+ saved_spats[0] = spats[0];
+ if (spats[0].pat != NULL) {
+ saved_spats[0].pat = xstrdup(spats[0].pat);
+ }
+ saved_spats[1] = spats[1];
+ if (spats[1].pat != NULL) {
+ saved_spats[1].pat = xstrdup(spats[1].pat);
}
+ if (mr_pattern == NULL) {
+ saved_mr_pattern = NULL;
+ } else {
+ saved_mr_pattern = xstrdup(mr_pattern);
+ }
+ saved_spats_last_idx = last_idx;
+ saved_spats_no_hlsearch = no_hlsearch;
}
void restore_search_patterns(void)
{
- if (--save_level == 0) {
- free_spat(&spats[0]);
- spats[0] = saved_spats[0];
- set_vv_searchforward();
- free_spat(&spats[1]);
- spats[1] = saved_spats[1];
- xfree(mr_pattern);
- mr_pattern = saved_mr_pattern;
- last_idx = saved_spats_last_idx;
- set_no_hlsearch(saved_spats_no_hlsearch);
+ if (--save_level != 0) {
+ return;
}
+
+ free_spat(&spats[0]);
+ spats[0] = saved_spats[0];
+ set_vv_searchforward();
+ free_spat(&spats[1]);
+ spats[1] = saved_spats[1];
+ xfree(mr_pattern);
+ mr_pattern = saved_mr_pattern;
+ last_idx = saved_spats_last_idx;
+ set_no_hlsearch(saved_spats_no_hlsearch);
}
static inline void free_spat(struct spat *const spat)
@@ -346,9 +352,9 @@ static void restore_incsearch_state(void)
search_match_lines = saved_search_match_lines;
}
-char_u *last_search_pattern(void)
+char *last_search_pattern(void)
{
- return (char_u *)spats[RE_SEARCH].pat;
+ return spats[RE_SEARCH].pat;
}
/// Return true when case should be ignored for search pattern "pat".
@@ -365,7 +371,7 @@ int ignorecase_opt(char *pat, int ic_in, int scs)
if (ic && !no_smartcase && scs
&& !(ctrl_x_mode_not_default()
&& curbuf->b_p_inf)) {
- ic = !pat_has_uppercase((char_u *)pat);
+ ic = !pat_has_uppercase(pat);
}
no_smartcase = false;
@@ -373,14 +379,14 @@ int ignorecase_opt(char *pat, int ic_in, int scs)
}
/// Returns true if pattern `pat` has an uppercase character.
-bool pat_has_uppercase(char_u *pat)
+bool pat_has_uppercase(char *pat)
FUNC_ATTR_NONNULL_ALL
{
- char *p = (char *)pat;
+ char *p = pat;
magic_T magic_val = MAGIC_ON;
// get the magicness of the pattern
- (void)skip_regexp_ex((char *)pat, NUL, magic_isset(), NULL, NULL, &magic_val);
+ (void)skip_regexp_ex(pat, NUL, magic_isset(), NULL, NULL, &magic_val);
while (*p != NUL) {
const int l = utfc_ptr2len(p);
@@ -431,7 +437,7 @@ int last_csearch_until(void)
return last_t_cmd == true;
}
-void set_last_csearch(int c, char_u *s, int len)
+void set_last_csearch(int c, char *s, int len)
{
*lastc = (char_u)c;
lastc_bytelen = len;
@@ -452,9 +458,9 @@ void set_csearch_until(int t_cmd)
last_t_cmd = t_cmd;
}
-char_u *last_search_pat(void)
+char *last_search_pat(void)
{
- return (char_u *)spats[last_idx].pat;
+ return spats[last_idx].pat;
}
// Reset search direction to forward. For "gd" and "gD" commands.
@@ -466,14 +472,14 @@ void reset_search_dir(void)
// Set the last search pattern. For ":let @/ =" and ShaDa file.
// Also set the saved search pattern, so that this works in an autocommand.
-void set_last_search_pat(const char_u *s, int idx, int magic, int setlast)
+void set_last_search_pat(const char *s, int idx, int magic, int setlast)
{
free_spat(&spats[idx]);
// An empty string means that nothing should be matched.
if (*s == NUL) {
spats[idx].pat = NULL;
} else {
- spats[idx].pat = xstrdup((char *)s);
+ spats[idx].pat = xstrdup(s);
}
spats[idx].timestamp = os_time();
spats[idx].additional_data = NULL;
@@ -513,7 +519,7 @@ void 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("", NULL, 0, last_idx, SEARCH_KEEP, regmatch);
emsg_off--;
}
@@ -540,7 +546,7 @@ void last_pat_prog(regmmatch_T *regmatch)
/// @returns FAIL (zero) for failure, non-zero for success.
/// the index of the first matching
/// subpattern plus one; one if there was none.
-int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, char_u *pat,
+int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, char *pat,
long count, int options, int pat_use, searchit_arg_T *extra_arg)
{
int found;
@@ -1296,7 +1302,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, long count, i
}
c = searchit(curwin, curbuf, &pos, NULL, dirc == '/' ? FORWARD : BACKWARD,
- (char_u *)searchstr, count,
+ searchstr, count,
(spats[0].off.end * SEARCH_END
+ (options
& (SEARCH_KEEP + SEARCH_PEEK + SEARCH_HIS + SEARCH_MSG
@@ -2321,55 +2327,63 @@ void showmatch(int c)
if ((lpos = findmatch(NULL, NUL)) == NULL) { // no match, so beep
vim_beep(BO_MATCH);
- } else if (lpos->lnum >= curwin->w_topline
- && lpos->lnum < curwin->w_botline) {
- if (!curwin->w_p_wrap) {
- getvcol(curwin, lpos, NULL, &vcol, NULL);
- }
- if (curwin->w_p_wrap
- || (vcol >= curwin->w_leftcol
- && vcol < curwin->w_leftcol + curwin->w_width_inner)) {
- mpos = *lpos; // save the pos, update_screen() may change it
- save_cursor = curwin->w_cursor;
- save_so = *so;
- save_siso = *siso;
- // Handle "$" in 'cpo': If the ')' is typed on top of the "$",
- // stop displaying the "$".
- if (dollar_vcol >= 0 && dollar_vcol == curwin->w_virtcol) {
- dollar_vcol = -1;
- }
- curwin->w_virtcol++; // do display ')' just before "$"
- update_screen(); // show the new char first
-
- save_dollar_vcol = dollar_vcol;
- save_state = State;
- State = MODE_SHOWMATCH;
- ui_cursor_shape(); // may show different cursor shape
- curwin->w_cursor = mpos; // move to matching char
- *so = 0; // don't use 'scrolloff' here
- *siso = 0; // don't use 'sidescrolloff' here
- show_cursor_info(false);
- setcursor();
- ui_flush();
- // Restore dollar_vcol(), because setcursor() may call curs_rows()
- // which resets it if the matching position is in a previous line
- // and has a higher column number.
- dollar_vcol = save_dollar_vcol;
-
- // brief pause, unless 'm' is present in 'cpo' and a character is
- // available.
- if (vim_strchr(p_cpo, CPO_SHOWMATCH) != NULL) {
- os_delay((uint64_t)p_mat * 100L + 8, true);
- } else if (!char_avail()) {
- os_delay((uint64_t)p_mat * 100L + 9, false);
- }
- curwin->w_cursor = save_cursor; // restore cursor position
- *so = save_so;
- *siso = save_siso;
- State = save_state;
- ui_cursor_shape(); // may show different cursor shape
- }
+ return;
+ }
+
+ if (lpos->lnum < curwin->w_topline || lpos->lnum >= curwin->w_botline) {
+ return;
+ }
+
+ if (!curwin->w_p_wrap) {
+ getvcol(curwin, lpos, NULL, &vcol, NULL);
+ }
+
+ bool col_visible = curwin->w_p_wrap
+ || (vcol >= curwin->w_leftcol
+ && vcol < curwin->w_leftcol + curwin->w_width_inner);
+ if (!col_visible) {
+ return;
+ }
+
+ mpos = *lpos; // save the pos, update_screen() may change it
+ save_cursor = curwin->w_cursor;
+ save_so = *so;
+ save_siso = *siso;
+ // Handle "$" in 'cpo': If the ')' is typed on top of the "$",
+ // stop displaying the "$".
+ if (dollar_vcol >= 0 && dollar_vcol == curwin->w_virtcol) {
+ dollar_vcol = -1;
}
+ curwin->w_virtcol++; // do display ')' just before "$"
+ update_screen(); // show the new char first
+
+ save_dollar_vcol = dollar_vcol;
+ save_state = State;
+ State = MODE_SHOWMATCH;
+ ui_cursor_shape(); // may show different cursor shape
+ curwin->w_cursor = mpos; // move to matching char
+ *so = 0; // don't use 'scrolloff' here
+ *siso = 0; // don't use 'sidescrolloff' here
+ show_cursor_info(false);
+ setcursor();
+ ui_flush();
+ // Restore dollar_vcol(), because setcursor() may call curs_rows()
+ // which resets it if the matching position is in a previous line
+ // and has a higher column number.
+ dollar_vcol = save_dollar_vcol;
+
+ // brief pause, unless 'm' is present in 'cpo' and a character is
+ // available.
+ if (vim_strchr(p_cpo, CPO_SHOWMATCH) != NULL) {
+ os_delay((uint64_t)p_mat * 100L + 8, true);
+ } else if (!char_avail()) {
+ os_delay((uint64_t)p_mat * 100L + 9, false);
+ }
+ curwin->w_cursor = save_cursor; // restore cursor position
+ *so = save_so;
+ *siso = save_siso;
+ State = save_state;
+ ui_cursor_shape(); // may show different cursor shape
}
/// Find next search match under cursor, cursor at end.
@@ -2440,7 +2454,7 @@ int current_search(long count, bool forward)
result = searchit(curwin, curbuf, &pos, &end_pos,
(dir ? FORWARD : BACKWARD),
- (char_u *)spats[last_idx].pat, i ? count : 1,
+ spats[last_idx].pat, i ? count : 1,
SEARCH_KEEP | flags, RE_SEARCH, NULL);
p_ws = old_p_ws;
@@ -2527,7 +2541,7 @@ static int is_zero_width(char *pattern, int move, pos_T *cur, Direction directio
pattern = spats[last_idx].pat;
}
- if (search_regcomp((char_u *)pattern, NULL, RE_SEARCH, RE_SEARCH,
+ if (search_regcomp(pattern, NULL, RE_SEARCH, RE_SEARCH,
SEARCH_KEEP, &regmatch) == FAIL) {
return -1;
}
@@ -2542,7 +2556,7 @@ static int is_zero_width(char *pattern, int move, pos_T *cur, Direction directio
// accept a match at the cursor position
flag = SEARCH_START;
}
- if (searchit(curwin, curbuf, &pos, NULL, direction, (char_u *)pattern, 1,
+ if (searchit(curwin, curbuf, &pos, NULL, direction, pattern, 1,
SEARCH_KEEP + flag, RE_SEARCH, NULL) != FAIL) {
// Zero-width pattern should match somewhere, then we can check if
// start and end are in the same position.
@@ -2588,56 +2602,63 @@ static void cmdline_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, bool sh
update_search_stat(dirc, pos, cursor_pos, &stat, recompute, maxcount,
timeout);
- if (stat.cur > 0) {
- char t[SEARCH_STAT_BUF_LEN];
-
- if (curwin->w_p_rl && *curwin->w_p_rlc == 's') {
- if (stat.incomplete == 1) {
- vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]");
- } else if (stat.cnt > maxcount && stat.cur > maxcount) {
- 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]",
- maxcount, stat.cur);
- } else {
- vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]",
- stat.cnt, stat.cur);
- }
+ if (stat.cur <= 0) {
+ return;
+ }
+
+ char t[SEARCH_STAT_BUF_LEN];
+
+ if (curwin->w_p_rl && *curwin->w_p_rlc == 's') {
+ if (stat.incomplete == 1) {
+ vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]");
+ } else if (stat.cnt > maxcount && stat.cur > maxcount) {
+ 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]",
+ maxcount, stat.cur);
} else {
- if (stat.incomplete == 1) {
- vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]");
- } else if (stat.cnt > maxcount && stat.cur > maxcount) {
- 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]",
- stat.cur, maxcount);
- } else {
- vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]",
- stat.cur, stat.cnt);
- }
+ vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]",
+ stat.cnt, stat.cur);
}
-
- size_t len = strlen(t);
- if (show_top_bot_msg && len + 2 < SEARCH_STAT_BUF_LEN) {
- memmove(t + 2, t, len);
- t[0] = 'W';
- t[1] = ' ';
- len += 2;
+ } else {
+ if (stat.incomplete == 1) {
+ vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]");
+ } else if (stat.cnt > maxcount && stat.cur > maxcount) {
+ 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]",
+ stat.cur, maxcount);
+ } else {
+ vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]",
+ stat.cur, stat.cnt);
}
+ }
- memmove(msgbuf + strlen(msgbuf) - len, t, len);
- if (dirc == '?' && stat.cur == maxcount + 1) {
- stat.cur = -1;
- }
+ size_t len = strlen(t);
+ if (show_top_bot_msg && len + 2 < SEARCH_STAT_BUF_LEN) {
+ memmove(t + 2, t, len);
+ t[0] = 'W';
+ t[1] = ' ';
+ len += 2;
+ }
+
+ size_t msgbuf_len = strlen(msgbuf);
+ if (len > msgbuf_len) {
+ len = msgbuf_len;
+ }
+ memmove(msgbuf + msgbuf_len - len, t, len);
- // keep the message even after redraw, but don't put in history
- msg_hist_off = true;
- msg_ext_set_kind("search_count");
- give_warning(msgbuf, false);
- msg_hist_off = false;
+ if (dirc == '?' && stat.cur == maxcount + 1) {
+ stat.cur = -1;
}
+
+ // keep the message even after redraw, but don't put in history
+ msg_hist_off = true;
+ msg_ext_set_kind("search_count");
+ give_warning(msgbuf, false);
+ msg_hist_off = false;
}
// Add the search count information to "stat".
@@ -2942,7 +2963,7 @@ typedef struct {
#define FUZZY_MATCH_RECURSION_LIMIT 10
/// Compute a score for a fuzzy matched string. The matching character locations
-/// are in 'matches'.
+/// are in "matches".
static int fuzzy_match_compute_score(const char *const str, const int strSz,
const uint32_t *const matches, const int numMatches)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
@@ -3007,7 +3028,7 @@ static int fuzzy_match_compute_score(const char *const str, const int strSz,
return score;
}
-/// Perform a recursive search for fuzzy matching 'fuzpat' in 'str'.
+/// Perform a recursive search for fuzzy matching "fuzpat" in "str".
/// @return the number of matching characters.
static int fuzzy_match_recursive(const char *fuzpat, const char *str, uint32_t strIdx,
int *const outScore, const char *const strBegin, const int strLen,
@@ -3107,23 +3128,23 @@ static int fuzzy_match_recursive(const char *fuzpat, const char *str, uint32_t s
/// Uses char_u for match indices. Therefore patterns are limited to
/// MAX_FUZZY_MATCHES characters.
///
-/// @return true if 'pat_arg' matches 'str'. Also returns the match score in
-/// 'outScore' and the matching character positions in 'matches'.
-bool fuzzy_match(char_u *const str, const char_u *const pat_arg, const bool matchseq,
+/// @return true if "pat_arg" matches "str". Also returns the match score in
+/// "outScore" and the matching character positions in "matches".
+bool fuzzy_match(char *const str, const char *const pat_arg, const bool matchseq,
int *const outScore, uint32_t *const matches, const int maxMatches)
- FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
+ FUNC_ATTR_NONNULL_ALL
{
- const int len = mb_charlen((char *)str);
+ const int len = mb_charlen(str);
bool complete = false;
int numMatches = 0;
*outScore = 0;
- char *const save_pat = xstrdup((char *)pat_arg);
+ char *const save_pat = xstrdup(pat_arg);
char *pat = save_pat;
char *p = pat;
- // Try matching each word in 'pat_arg' in 'str'
+ // Try matching each word in "pat_arg" in "str"
while (true) {
if (matchseq) {
complete = true;
@@ -3146,7 +3167,7 @@ bool fuzzy_match(char_u *const str, const char_u *const pat_arg, const bool matc
int score = 0;
int recursionCount = 0;
const int matchCount
- = fuzzy_match_recursive(pat, (char *)str, 0, &score, (char *)str, len, NULL,
+ = fuzzy_match_recursive(pat, str, 0, &score, str, len, NULL,
matches + numMatches,
maxMatches - numMatches, 0, &recursionCount);
if (matchCount == 0) {
@@ -3183,14 +3204,14 @@ static int fuzzy_match_item_compare(const void *const s1, const void *const s2)
return v1 == v2 ? (idx1 - idx2) : v1 > v2 ? -1 : 1;
}
-/// Fuzzy search the string 'str' in a list of 'items' and return the matching
-/// strings in 'fmatchlist'.
-/// If 'matchseq' is true, then for multi-word search strings, match all the
+/// Fuzzy search the string "str" in a list of "items" and return the matching
+/// strings in "fmatchlist".
+/// If "matchseq" is true, then for multi-word search strings, match all the
/// words in sequence.
-/// If 'items' is a list of strings, then search for 'str' in the list.
-/// If 'items' is a list of dicts, then either use 'key' to lookup the string
-/// for each item or use 'item_cb' Funcref function to get the string.
-/// If 'retmatchpos' is true, then return a list of positions where 'str'
+/// If "items" is a list of strings, then search for "str" in the list.
+/// If "items" is a list of dicts, then either use "key" to lookup the string
+/// for each item or use "item_cb" Funcref function to get the string.
+/// If "retmatchpos" is true, then return a list of positions where "str"
/// matches for each item.
static void fuzzy_match_in_list(list_T *const l, char *const str, const bool matchseq,
const char *const key, Callback *const item_cb,
@@ -3245,14 +3266,14 @@ static void fuzzy_match_in_list(list_T *const l, char *const str, const bool mat
}
int score;
- if (itemstr != NULL && fuzzy_match((char_u *)itemstr, (char_u *)str, matchseq, &score, matches,
+ if (itemstr != NULL && fuzzy_match(itemstr, str, matchseq, &score, matches,
MAX_FUZZY_MATCHES)) {
items[match_count].idx = (int)match_count;
items[match_count].item = li;
items[match_count].score = score;
// Copy the list of matching positions in itemstr to a list, if
- // 'retmatchpos' is set.
+ // "retmatchpos" is set.
if (retmatchpos) {
items[match_count].lmatchpos = tv_list_alloc(kListLenMayKnow);
int j = 0;
@@ -3326,8 +3347,8 @@ static void fuzzy_match_in_list(list_T *const l, char *const str, const bool mat
xfree(items);
}
-/// Do fuzzy matching. Returns the list of matched strings in 'rettv'.
-/// If 'retmatchpos' is true, also returns the matching character positions.
+/// Do fuzzy matching. Returns the list of matched strings in "rettv".
+/// If "retmatchpos" is true, also returns the matching character positions.
static void do_fuzzymatch(const typval_T *const argvars, typval_T *const rettv,
const bool retmatchpos)
FUNC_ATTR_NONNULL_ALL
@@ -3411,6 +3432,109 @@ void f_matchfuzzypos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
do_fuzzymatch(argvars, rettv, true);
}
+/// Same as fuzzy_match_item_compare() except for use with a string match
+static int fuzzy_match_str_compare(const void *const s1, const void *const s2)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE
+{
+ const int v1 = ((fuzmatch_str_T *)s1)->score;
+ const int v2 = ((fuzmatch_str_T *)s2)->score;
+ const int idx1 = ((fuzmatch_str_T *)s1)->idx;
+ const int idx2 = ((fuzmatch_str_T *)s2)->idx;
+
+ return v1 == v2 ? (idx1 - idx2) : v1 > v2 ? -1 : 1;
+}
+
+/// Sort fuzzy matches by score
+static void fuzzy_match_str_sort(fuzmatch_str_T *const fm, const int sz)
+ FUNC_ATTR_NONNULL_ALL
+{
+ // Sort the list by the descending order of the match score
+ qsort(fm, (size_t)sz, sizeof(fuzmatch_str_T), fuzzy_match_str_compare);
+}
+
+/// Same as fuzzy_match_item_compare() except for use with a function name
+/// string match. <SNR> functions should be sorted to the end.
+static int fuzzy_match_func_compare(const void *const s1, const void *const s2)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE
+{
+ const int v1 = ((fuzmatch_str_T *)s1)->score;
+ const int v2 = ((fuzmatch_str_T *)s2)->score;
+ const int idx1 = ((fuzmatch_str_T *)s1)->idx;
+ const int idx2 = ((fuzmatch_str_T *)s2)->idx;
+ const char *const str1 = ((fuzmatch_str_T *)s1)->str;
+ const char *const str2 = ((fuzmatch_str_T *)s2)->str;
+
+ if (*str1 != '<' && *str2 == '<') {
+ return -1;
+ }
+ if (*str1 == '<' && *str2 != '<') {
+ return 1;
+ }
+ return v1 == v2 ? (idx1 - idx2) : v1 > v2 ? -1 : 1;
+}
+
+/// Sort fuzzy matches of function names by score.
+/// <SNR> functions should be sorted to the end.
+static void fuzzy_match_func_sort(fuzmatch_str_T *const fm, const int sz)
+ FUNC_ATTR_NONNULL_ALL
+{
+ // Sort the list by the descending order of the match score
+ qsort(fm, (size_t)sz, sizeof(fuzmatch_str_T), fuzzy_match_func_compare);
+}
+
+/// Fuzzy match "pat" in "str".
+/// @returns 0 if there is no match. Otherwise, returns the match score.
+int fuzzy_match_str(char *const str, const char *const pat)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ if (str == NULL || pat == NULL) {
+ return 0;
+ }
+
+ int score = 0;
+ uint32_t matchpos[MAX_FUZZY_MATCHES];
+ fuzzy_match(str, pat, true, &score, matchpos, sizeof(matchpos) / sizeof(matchpos[0]));
+
+ return score;
+}
+
+/// Copy a list of fuzzy matches into a string list after sorting the matches by
+/// the fuzzy score. Frees the memory allocated for "fuzmatch".
+void fuzzymatches_to_strmatches(fuzmatch_str_T *const fuzmatch, char ***const matches,
+ const int count, const bool funcsort)
+ FUNC_ATTR_NONNULL_ARG(2)
+{
+ if (count <= 0) {
+ return;
+ }
+
+ *matches = xmalloc((size_t)count * sizeof(char *));
+
+ // Sort the list by the descending order of the match score
+ if (funcsort) {
+ fuzzy_match_func_sort(fuzmatch, count);
+ } else {
+ fuzzy_match_str_sort(fuzmatch, count);
+ }
+
+ for (int i = 0; i < count; i++) {
+ (*matches)[i] = fuzmatch[i].str;
+ }
+ xfree(fuzmatch);
+}
+
+/// Free a list of fuzzy string matches.
+void fuzmatch_str_free(fuzmatch_str_T *const fuzmatch, int count)
+{
+ if (count <= 0 || fuzmatch == NULL) {
+ return;
+ }
+ while (count--) {
+ xfree(fuzmatch[count].str);
+ }
+ xfree(fuzmatch);
+}
+
/// Get line "lnum" and copy it into "buf[LSIZE]".
/// The copy is made because the regexp may make the line invalid when using a
/// mark.
@@ -3534,9 +3658,9 @@ void find_pattern_in_path(char *ptr, Direction dir, size_t len, bool whole, bool
1L, p_fname);
} else {
// Use text after match with 'include'.
- new_fname = (char *)file_name_in_line((char_u *)incl_regmatch.endp[0], 0,
- FNAME_EXP|FNAME_INCL|FNAME_REL, 1L, (char_u *)p_fname,
- NULL);
+ new_fname = file_name_in_line(incl_regmatch.endp[0], 0,
+ FNAME_EXP|FNAME_INCL|FNAME_REL, 1L, p_fname,
+ NULL);
}
already_searched = false;
if (new_fname != NULL) {