Skip to content

Commit bb01a1e

Browse files
yegappanbrammool
authored andcommitted
patch 8.2.2813: cannot grep using fuzzy matching
Problem: Cannot grep using fuzzy matching. Solution: Add the "f" flag to :vimgrep. (Yegappan Lakshmanan, closes #8152)
1 parent 5930ddc commit bb01a1e

File tree

8 files changed

+160
-62
lines changed

8 files changed

+160
-62
lines changed

runtime/doc/quickfix.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,7 +1008,7 @@ commands can be combined to create a NewGrep command: >
10081008
5.1 using Vim's internal grep
10091009

10101010
*:vim* *:vimgrep* *E682* *E683*
1011-
:vim[grep][!] /{pattern}/[g][j] {file} ...
1011+
:vim[grep][!] /{pattern}/[g][j][f] {file} ...
10121012
Search for {pattern} in the files {file} ... and set
10131013
the error list to the matches. Files matching
10141014
'wildignore' are ignored; files in 'suffixes' are
@@ -1059,20 +1059,20 @@ commands can be combined to create a NewGrep command: >
10591059
:vimgrep Error *.c
10601060
<
10611061
*:lv* *:lvimgrep*
1062-
:lv[imgrep][!] /{pattern}/[g][j] {file} ...
1062+
:lv[imgrep][!] /{pattern}/[g][j][f] {file} ...
10631063
:lv[imgrep][!] {pattern} {file} ...
10641064
Same as ":vimgrep", except the location list for the
10651065
current window is used instead of the quickfix list.
10661066

10671067
*:vimgrepa* *:vimgrepadd*
1068-
:vimgrepa[dd][!] /{pattern}/[g][j] {file} ...
1068+
:vimgrepa[dd][!] /{pattern}/[g][j][f] {file} ...
10691069
:vimgrepa[dd][!] {pattern} {file} ...
10701070
Just like ":vimgrep", but instead of making a new list
10711071
of errors the matches are appended to the current
10721072
list.
10731073

10741074
*:lvimgrepa* *:lvimgrepadd*
1075-
:lvimgrepa[dd][!] /{pattern}/[g][j] {file} ...
1075+
:lvimgrepa[dd][!] /{pattern}/[g][j][f] {file} ...
10761076
:lvimgrepa[dd][!] {pattern} {file} ...
10771077
Same as ":vimgrepadd", except the location list for
10781078
the current window is used instead of the quickfix

src/ex_cmds.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5288,14 +5288,16 @@ skip_vimgrep_pat(char_u *p, char_u **s, int *flags)
52885288
++p;
52895289

52905290
// Find the flags
5291-
while (*p == 'g' || *p == 'j')
5291+
while (*p == 'g' || *p == 'j' || *p == 'f')
52925292
{
52935293
if (flags != NULL)
52945294
{
52955295
if (*p == 'g')
52965296
*flags |= VGR_GLOBAL;
5297-
else
5297+
else if (*p == 'j')
52985298
*flags |= VGR_NOJUMP;
5299+
else
5300+
*flags |= VGR_FUZZY;
52995301
}
53005302
++p;
53015303
}

src/proto/search.pro

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ void find_pattern_in_path(char_u *ptr, int dir, int len, int whole, int skip_com
3636
spat_T *get_spat(int idx);
3737
int get_spat_last_idx(void);
3838
void f_searchcount(typval_T *argvars, typval_T *rettv);
39+
int fuzzy_match(char_u *str, char_u *pat_arg, int matchseq, int *outScore, int_u *matches, int maxMatches);
3940
void f_matchfuzzy(typval_T *argvars, typval_T *rettv);
4041
void f_matchfuzzypos(typval_T *argvars, typval_T *rettv);
4142
/* vim: set ft=c : */

src/quickfix.c

Lines changed: 80 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5912,6 +5912,7 @@ vgr_match_buflines(
59125912
qf_list_T *qfl,
59135913
char_u *fname,
59145914
buf_T *buf,
5915+
char_u *spat,
59155916
regmmatch_T *regmatch,
59165917
long *tomatch,
59175918
int duplicate_name,
@@ -5920,45 +5921,91 @@ vgr_match_buflines(
59205921
int found_match = FALSE;
59215922
long lnum;
59225923
colnr_T col;
5924+
int pat_len = STRLEN(spat);
59235925

59245926
for (lnum = 1; lnum <= buf->b_ml.ml_line_count && *tomatch > 0; ++lnum)
59255927
{
59265928
col = 0;
5927-
while (vim_regexec_multi(regmatch, curwin, buf, lnum,
5928-
col, NULL, NULL) > 0)
5929+
if (!(flags & VGR_FUZZY))
59295930
{
5930-
// Pass the buffer number so that it gets used even for a
5931-
// dummy buffer, unless duplicate_name is set, then the
5932-
// buffer will be wiped out below.
5933-
if (qf_add_entry(qfl,
5934-
NULL, // dir
5935-
fname,
5936-
NULL,
5937-
duplicate_name ? 0 : buf->b_fnum,
5938-
ml_get_buf(buf,
5939-
regmatch->startpos[0].lnum + lnum, FALSE),
5940-
regmatch->startpos[0].lnum + lnum,
5941-
regmatch->startpos[0].col + 1,
5942-
FALSE, // vis_col
5943-
NULL, // search pattern
5944-
0, // nr
5945-
0, // type
5946-
TRUE // valid
5947-
) == QF_FAIL)
5931+
// Regular expression match
5932+
while (vim_regexec_multi(regmatch, curwin, buf, lnum,
5933+
col, NULL, NULL) > 0)
59485934
{
5949-
got_int = TRUE;
5950-
break;
5935+
// Pass the buffer number so that it gets used even for a
5936+
// dummy buffer, unless duplicate_name is set, then the
5937+
// buffer will be wiped out below.
5938+
if (qf_add_entry(qfl,
5939+
NULL, // dir
5940+
fname,
5941+
NULL,
5942+
duplicate_name ? 0 : buf->b_fnum,
5943+
ml_get_buf(buf,
5944+
regmatch->startpos[0].lnum + lnum, FALSE),
5945+
regmatch->startpos[0].lnum + lnum,
5946+
regmatch->startpos[0].col + 1,
5947+
FALSE, // vis_col
5948+
NULL, // search pattern
5949+
0, // nr
5950+
0, // type
5951+
TRUE // valid
5952+
) == QF_FAIL)
5953+
{
5954+
got_int = TRUE;
5955+
break;
5956+
}
5957+
found_match = TRUE;
5958+
if (--*tomatch == 0)
5959+
break;
5960+
if ((flags & VGR_GLOBAL) == 0
5961+
|| regmatch->endpos[0].lnum > 0)
5962+
break;
5963+
col = regmatch->endpos[0].col
5964+
+ (col == regmatch->endpos[0].col);
5965+
if (col > (colnr_T)STRLEN(ml_get_buf(buf, lnum, FALSE)))
5966+
break;
5967+
}
5968+
}
5969+
else
5970+
{
5971+
char_u *str = ml_get_buf(buf, lnum, FALSE);
5972+
int score;
5973+
int_u matches[MAX_FUZZY_MATCHES];
5974+
int_u sz = sizeof(matches) / sizeof(matches[0]);
5975+
5976+
// Fuzzy string match
5977+
while (fuzzy_match(str + col, spat, FALSE, &score, matches, sz) > 0)
5978+
{
5979+
// Pass the buffer number so that it gets used even for a
5980+
// dummy buffer, unless duplicate_name is set, then the
5981+
// buffer will be wiped out below.
5982+
if (qf_add_entry(qfl,
5983+
NULL, // dir
5984+
fname,
5985+
NULL,
5986+
duplicate_name ? 0 : buf->b_fnum,
5987+
str,
5988+
lnum,
5989+
matches[0] + col + 1,
5990+
FALSE, // vis_col
5991+
NULL, // search pattern
5992+
0, // nr
5993+
0, // type
5994+
TRUE // valid
5995+
) == QF_FAIL)
5996+
{
5997+
got_int = TRUE;
5998+
break;
5999+
}
6000+
found_match = TRUE;
6001+
if (--*tomatch == 0)
6002+
break;
6003+
if ((flags & VGR_GLOBAL) == 0)
6004+
break;
6005+
col = matches[pat_len - 1] + col + 1;
6006+
if (col > (colnr_T)STRLEN(str))
6007+
break;
59516008
}
5952-
found_match = TRUE;
5953-
if (--*tomatch == 0)
5954-
break;
5955-
if ((flags & VGR_GLOBAL) == 0
5956-
|| regmatch->endpos[0].lnum > 0)
5957-
break;
5958-
col = regmatch->endpos[0].col
5959-
+ (col == regmatch->endpos[0].col);
5960-
if (col > (colnr_T)STRLEN(ml_get_buf(buf, lnum, FALSE)))
5961-
break;
59626009
}
59636010
line_breakcheck();
59646011
if (got_int)
@@ -6163,7 +6210,7 @@ vgr_process_files(
61636210
// Try for a match in all lines of the buffer.
61646211
// For ":1vimgrep" look for first match only.
61656212
found_match = vgr_match_buflines(qf_get_curlist(qi),
6166-
fname, buf, &cmd_args->regmatch,
6213+
fname, buf, cmd_args->spat, &cmd_args->regmatch,
61676214
&cmd_args->tomatch, duplicate_name, cmd_args->flags);
61686215

61696216
if (using_dummy)

src/search.c

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4285,10 +4285,6 @@ typedef struct
42854285
#define SCORE_NONE -9999
42864286

42874287
#define FUZZY_MATCH_RECURSION_LIMIT 10
4288-
// Maximum number of characters that can be fuzzy matched
4289-
#define MAXMATCHES 256
4290-
4291-
typedef int_u matchidx_T;
42924288

42934289
/*
42944290
* Compute a score for a fuzzy matched string. The matching character locations
@@ -4298,15 +4294,15 @@ typedef int_u matchidx_T;
42984294
fuzzy_match_compute_score(
42994295
char_u *str,
43004296
int strSz,
4301-
matchidx_T *matches,
4297+
int_u *matches,
43024298
int numMatches)
43034299
{
43044300
int score;
43054301
int penalty;
43064302
int unmatched;
43074303
int i;
43084304
char_u *p = str;
4309-
matchidx_T sidx = 0;
4305+
int_u sidx = 0;
43104306

43114307
// Initialize score
43124308
score = 100;
@@ -4324,11 +4320,11 @@ fuzzy_match_compute_score(
43244320
// Apply ordering bonuses
43254321
for (i = 0; i < numMatches; ++i)
43264322
{
4327-
matchidx_T currIdx = matches[i];
4323+
int_u currIdx = matches[i];
43284324

43294325
if (i > 0)
43304326
{
4331-
matchidx_T prevIdx = matches[i - 1];
4327+
int_u prevIdx = matches[i - 1];
43324328

43334329
// Sequential
43344330
if (currIdx == (prevIdx + 1))
@@ -4386,19 +4382,19 @@ fuzzy_match_compute_score(
43864382
fuzzy_match_recursive(
43874383
char_u *fuzpat,
43884384
char_u *str,
4389-
matchidx_T strIdx,
4385+
int_u strIdx,
43904386
int *outScore,
43914387
char_u *strBegin,
43924388
int strLen,
4393-
matchidx_T *srcMatches,
4394-
matchidx_T *matches,
4389+
int_u *srcMatches,
4390+
int_u *matches,
43954391
int maxMatches,
43964392
int nextMatch,
43974393
int *recursionCount)
43984394
{
43994395
// Recursion params
44004396
int recursiveMatch = FALSE;
4401-
matchidx_T bestRecursiveMatches[MAXMATCHES];
4397+
int_u bestRecursiveMatches[MAX_FUZZY_MATCHES];
44024398
int bestRecursiveScore = 0;
44034399
int first_match;
44044400
int matched;
@@ -4409,7 +4405,7 @@ fuzzy_match_recursive(
44094405
return 0;
44104406

44114407
// Detect end of strings
4412-
if (*fuzpat == '\0' || *str == '\0')
4408+
if (*fuzpat == NUL || *str == NUL)
44134409
return 0;
44144410

44154411
// Loop through fuzpat and str looking for a match
@@ -4425,7 +4421,7 @@ fuzzy_match_recursive(
44254421
// Found match
44264422
if (vim_tolower(c1) == vim_tolower(c2))
44274423
{
4428-
matchidx_T recursiveMatches[MAXMATCHES];
4424+
int_u recursiveMatches[MAX_FUZZY_MATCHES];
44294425
int recursiveScore = 0;
44304426
char_u *next_char;
44314427

@@ -4455,7 +4451,7 @@ fuzzy_match_recursive(
44554451
if (!recursiveMatch || recursiveScore > bestRecursiveScore)
44564452
{
44574453
memcpy(bestRecursiveMatches, recursiveMatches,
4458-
MAXMATCHES * sizeof(recursiveMatches[0]));
4454+
MAX_FUZZY_MATCHES * sizeof(recursiveMatches[0]));
44594455
bestRecursiveScore = recursiveScore;
44604456
}
44614457
recursiveMatch = TRUE;
@@ -4506,19 +4502,19 @@ fuzzy_match_recursive(
45064502
* normalized and varies with pattern.
45074503
* Recursion is limited internally (default=10) to prevent degenerate cases
45084504
* (pat_arg="aaaaaa" str="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").
4509-
* Uses char_u for match indices. Therefore patterns are limited to MAXMATCHES
4510-
* characters.
4505+
* Uses char_u for match indices. Therefore patterns are limited to
4506+
* MAX_FUZZY_MATCHES characters.
45114507
*
45124508
* Returns TRUE if 'pat_arg' matches 'str'. Also returns the match score in
45134509
* 'outScore' and the matching character positions in 'matches'.
45144510
*/
4515-
static int
4511+
int
45164512
fuzzy_match(
45174513
char_u *str,
45184514
char_u *pat_arg,
45194515
int matchseq,
45204516
int *outScore,
4521-
matchidx_T *matches,
4517+
int_u *matches,
45224518
int maxMatches)
45234519
{
45244520
int recursionCount = 0;
@@ -4630,7 +4626,7 @@ fuzzy_match_in_list(
46304626
listitem_T *li;
46314627
long i = 0;
46324628
int found_match = FALSE;
4633-
matchidx_T matches[MAXMATCHES];
4629+
int_u matches[MAX_FUZZY_MATCHES];
46344630

46354631
len = list_len(items);
46364632
if (len == 0)
@@ -4847,7 +4843,7 @@ do_fuzzymatch(typval_T *argvars, typval_T *rettv, int retmatchpos)
48474843
return;
48484844
}
48494845
}
4850-
if ((di = dict_find(d, (char_u *)"matchseq", -1)) != NULL)
4846+
if (dict_find(d, (char_u *)"matchseq", -1) != NULL)
48514847
matchseq = TRUE;
48524848
}
48534849

0 commit comments

Comments
 (0)