vim-patch:8.2.4463: completion only uses strict matching

Problem:    Completion only uses strict matching.
Solution:   Add the "fuzzy" item for 'wildoptions'. (Yegappan Lakshmanan,
            closes vim/vim#9803)

38b85cb4d7

Use MAX_FUZZY_MATCHES in fuzzy_match_str().
Omit fuzmatch_str_free() as it is only used on allocation failure.

Co-authored-by: Yegappan Lakshmanan <yegappan@yahoo.com>
This commit is contained in:
Sean Dewar
2022-02-20 00:18:15 +00:00
committed by zeertzjq
parent 34e62d3875
commit 6734dd2503
9 changed files with 693 additions and 76 deletions

View File

@@ -88,6 +88,7 @@
#include "nvim/regexp.h"
#include "nvim/runtime.h"
#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/sign.h"
#include "nvim/spell.h"
#include "nvim/statusline.h"
@@ -2337,7 +2338,6 @@ int ExpandBufnames(char *pat, int *num_file, char ***file, int options)
int round;
char *p;
int attempt;
char *patc;
bufmatch_T *matches = NULL;
*num_file = 0; // return values in case of FAIL
@@ -2347,31 +2347,40 @@ int ExpandBufnames(char *pat, int *num_file, char ***file, int options)
return FAIL;
}
// Make a copy of "pat" and change "^" to "\(^\|[\/]\)".
if (*pat == '^') {
patc = xmalloc(strlen(pat) + 11);
STRCPY(patc, "\\(^\\|[\\/]\\)");
STRCPY(patc + 11, pat + 1);
} else {
patc = pat;
const bool fuzzy = cmdline_fuzzy_complete(pat);
char *patc = NULL;
// Make a copy of "pat" and change "^" to "\(^\|[\/]\)" (if doing regular
// expression matching)
if (!fuzzy) {
if (*pat == '^') {
patc = xmalloc(strlen(pat) + 11);
STRCPY(patc, "\\(^\\|[\\/]\\)");
STRCPY(patc + 11, pat + 1);
} else {
patc = pat;
}
}
fuzmatch_str_T *fuzmatch = NULL;
// attempt == 0: try match with '\<', match at start of word
// attempt == 1: try match without '\<', match anywhere
for (attempt = 0; attempt <= 1; attempt++) {
if (attempt > 0 && patc == pat) {
break; // there was no anchor, no need to try again
}
for (attempt = 0; attempt <= (fuzzy ? 0 : 1); attempt++) {
regmatch_T regmatch;
regmatch.regprog = vim_regcomp(patc + attempt * 11, RE_MAGIC);
if (regmatch.regprog == NULL) {
if (patc != pat) {
xfree(patc);
if (!fuzzy) {
if (attempt > 0 && patc == pat) {
break; // there was no anchor, no need to try again
}
regmatch.regprog = vim_regcomp(patc + attempt * 11, RE_MAGIC);
if (regmatch.regprog == NULL) {
if (patc != pat) {
xfree(patc);
}
return FAIL;
}
return FAIL;
}
int score = 0;
// round == 1: Count the matches.
// round == 2: Build the array to keep the matches.
for (round = 1; round <= 2; round++) {
@@ -2387,7 +2396,23 @@ int ExpandBufnames(char *pat, int *num_file, char ***file, int options)
continue;
}
}
p = buflist_match(&regmatch, buf, p_wic);
if (!fuzzy) {
p = buflist_match(&regmatch, buf, p_wic);
} else {
p = NULL;
// first try matching with the short file name
if ((score = fuzzy_match_str(buf->b_sfname, pat)) != 0) {
p = buf->b_sfname;
}
if (p == NULL) {
// next try matching with the full path file name
if ((score = fuzzy_match_str(buf->b_ffname, pat)) != 0) {
p = buf->b_ffname;
}
}
}
if (p != NULL) {
if (round == 1) {
count++;
@@ -2397,12 +2422,20 @@ int ExpandBufnames(char *pat, int *num_file, char ***file, int options)
} else {
p = xstrdup(p);
}
if (matches != NULL) {
matches[count].buf = buf;
matches[count].match = p;
count++;
if (!fuzzy) {
if (matches != NULL) {
matches[count].buf = buf;
matches[count].match = p;
count++;
} else {
(*file)[count++] = p;
}
} else {
(*file)[count++] = p;
fuzmatch[count].idx = count;
fuzmatch[count].str = p;
fuzmatch[count].score = score;
count++;
}
}
}
@@ -2411,40 +2444,50 @@ int ExpandBufnames(char *pat, int *num_file, char ***file, int options)
break;
}
if (round == 1) {
*file = xmalloc((size_t)count * sizeof(**file));
if (options & WILD_BUFLASTUSED) {
matches = xmalloc((size_t)count * sizeof(*matches));
if (!fuzzy) {
*file = xmalloc((size_t)count * sizeof(**file));
if (options & WILD_BUFLASTUSED) {
matches = xmalloc((size_t)count * sizeof(*matches));
}
} else {
fuzmatch = xmalloc((size_t)count * sizeof(fuzmatch_str_T));
}
}
}
vim_regfree(regmatch.regprog);
if (count) { // match(es) found, break here
break;
if (!fuzzy) {
vim_regfree(regmatch.regprog);
if (count) { // match(es) found, break here
break;
}
}
}
if (patc != pat) {
if (!fuzzy && patc != pat) {
xfree(patc);
}
if (matches != NULL) {
if (count > 1) {
qsort(matches, (size_t)count, sizeof(bufmatch_T), buf_time_compare);
}
if (!fuzzy) {
if (matches != NULL) {
if (count > 1) {
qsort(matches, (size_t)count, sizeof(bufmatch_T), buf_time_compare);
}
// if the current buffer is first in the list, place it at the end
if (matches[0].buf == curbuf) {
for (int i = 1; i < count; i++) {
(*file)[i - 1] = matches[i].match;
}
(*file)[count - 1] = matches[0].match;
} else {
for (int i = 0; i < count; i++) {
(*file)[i] = matches[i].match;
// if the current buffer is first in the list, place it at the end
if (matches[0].buf == curbuf) {
for (int i = 1; i < count; i++) {
(*file)[i - 1] = matches[i].match;
}
(*file)[count - 1] = matches[0].match;
} else {
for (int i = 0; i < count; i++) {
(*file)[i] = matches[i].match;
}
}
xfree(matches);
}
xfree(matches);
} else {
fuzzymatches_to_strmatches(fuzmatch, file, count, false);
}
*num_file = count;