diff src/buffer.c @ 27875:ae38d2e81fca v8.2.4463

patch 8.2.4463: completion only uses strict matching Commit: https://github.com/vim/vim/commit/38b85cb4d7216705058708bacbc25ab90cd61595 Author: Yegappan Lakshmanan <yegappan@yahoo.com> Date: Thu Feb 24 13:28:41 2022 +0000 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 #9803)
author Bram Moolenaar <Bram@vim.org>
date Thu, 24 Feb 2022 14:30:05 +0100
parents fa675efa1e75
children 6efa2f193c94
line wrap: on
line diff
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -2728,10 +2728,12 @@ ExpandBufnames(
     int		round;
     char_u	*p;
     int		attempt;
-    char_u	*patc;
+    char_u	*patc = NULL;
 #ifdef FEAT_VIMINFO
     bufmatch_T	*matches = NULL;
 #endif
+    int		fuzzy;
+    fuzmatch_str_T  *fuzmatch = NULL;
 
     *num_file = 0;		    // return values in case of FAIL
     *file = NULL;
@@ -2741,32 +2743,42 @@ ExpandBufnames(
 	return FAIL;
 #endif
 
-    // Make a copy of "pat" and change "^" to "\(^\|[\/]\)".
-    if (*pat == '^')
+    fuzzy = cmdline_fuzzy_complete(pat);
+
+    // Make a copy of "pat" and change "^" to "\(^\|[\/]\)" (if doing regular
+    // expression matching)
+    if (!fuzzy)
     {
-	patc = alloc(STRLEN(pat) + 11);
-	if (patc == NULL)
-	    return FAIL;
-	STRCPY(patc, "\\(^\\|[\\/]\\)");
-	STRCPY(patc + 11, pat + 1);
+	if (*pat == '^')
+	{
+	    patc = alloc(STRLEN(pat) + 11);
+	    if (patc == NULL)
+		return FAIL;
+	    STRCPY(patc, "\\(^\\|[\\/]\\)");
+	    STRCPY(patc + 11, pat + 1);
+	}
+	else
+	    patc = pat;
     }
-    else
-	patc = pat;
 
     // attempt == 0: try match with    '\<', match at start of word
     // attempt == 1: try match without '\<', match anywhere
-    for (attempt = 0; attempt <= 1; ++attempt)
+    for (attempt = 0; attempt <= (fuzzy ? 0 : 1); ++attempt)
     {
 	regmatch_T	regmatch;
-
-	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)
+	int		score = 0;
+
+	if (!fuzzy)
 	{
-	    if (patc != pat)
-		vim_free(patc);
-	    return FAIL;
+	    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)
+		    vim_free(patc);
+		return FAIL;
+	    }
 	}
 
 	// round == 1: Count the matches.
@@ -2786,7 +2798,22 @@ ExpandBufnames(
 			continue;
 #endif
 
-		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)
@@ -2797,16 +2824,27 @@ ExpandBufnames(
 			    p = home_replace_save(buf, p);
 			else
 			    p = vim_strsave(p);
-#ifdef FEAT_VIMINFO
-			if (matches != NULL)
+
+			if (!fuzzy)
 			{
-			    matches[count].buf = buf;
-			    matches[count].match = p;
+#ifdef FEAT_VIMINFO
+			    if (matches != NULL)
+			    {
+				matches[count].buf = buf;
+				matches[count].match = p;
+				count++;
+			    }
+			    else
+#endif
+				(*file)[count++] = p;
+			}
+			else
+			{
+			    fuzmatch[count].idx = count;
+			    fuzmatch[count].str = p;
+			    fuzmatch[count].score = score;
 			    count++;
 			}
-			else
-#endif
-			    (*file)[count++] = p;
 		    }
 		}
 	    }
@@ -2814,47 +2852,72 @@ ExpandBufnames(
 		break;
 	    if (round == 1)
 	    {
-		*file = ALLOC_MULT(char_u *, count);
-		if (*file == NULL)
+		if (!fuzzy)
 		{
-		    vim_regfree(regmatch.regprog);
-		    if (patc != pat)
-			vim_free(patc);
-		    return FAIL;
+		    *file = ALLOC_MULT(char_u *, count);
+		    if (*file == NULL)
+		    {
+			vim_regfree(regmatch.regprog);
+			if (patc != pat)
+			    vim_free(patc);
+			return FAIL;
+		    }
+#ifdef FEAT_VIMINFO
+		    if (options & WILD_BUFLASTUSED)
+			matches = ALLOC_MULT(bufmatch_T, count);
+#endif
 		}
-#ifdef FEAT_VIMINFO
-		if (options & WILD_BUFLASTUSED)
-		    matches = ALLOC_MULT(bufmatch_T, count);
-#endif
+		else
+		{
+		    fuzmatch = ALLOC_MULT(fuzmatch_str_T, count);
+		    if (fuzmatch == NULL)
+		    {
+			*num_file = 0;
+			*file = NULL;
+			return FAIL;
+		    }
+		}
 	    }
 	}
-	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)
 	vim_free(patc);
 
 #ifdef FEAT_VIMINFO
-    if (matches != NULL)
+    if (!fuzzy)
     {
-	int i;
-	if (count > 1)
-	    qsort(matches, count, sizeof(bufmatch_T), buf_compare);
-	// if the current buffer is first in the list, place it at the end
-	if (matches[0].buf == curbuf)
+	if (matches != NULL)
 	{
-	    for (i = 1; i < count; i++)
-		(*file)[i-1] = matches[i].match;
-	    (*file)[count-1] = matches[0].match;
+	    int i;
+	    if (count > 1)
+		qsort(matches, count, sizeof(bufmatch_T), buf_compare);
+	    // if the current buffer is first in the list, place it at the end
+	    if (matches[0].buf == curbuf)
+	    {
+		for (i = 1; i < count; i++)
+		    (*file)[i-1] = matches[i].match;
+		(*file)[count-1] = matches[0].match;
+	    }
+	    else
+	    {
+		for (i = 0; i < count; i++)
+		    (*file)[i] = matches[i].match;
+	    }
+	    vim_free(matches);
 	}
-	else
-	{
-	    for (i = 0; i < count; i++)
-		(*file)[i] = matches[i].match;
-	}
-	vim_free(matches);
+    }
+    else
+    {
+	if (fuzzymatches_to_strmatches(fuzmatch, file, count, FALSE) == FAIL)
+	    return FAIL;
     }
 #endif