patch 9.1.0605: internal error with fuzzy completion

Problem:  internal error with fuzzy completion
          (techntools)
Solution: only fuzzy complete the pattern after directory separator
          (glepnir)

fixes: #15287
closes: #15291

Signed-off-by: glepnir <glephunter@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/insexpand.c b/src/insexpand.c
index fa4ac7d..4ad1f41 100644
--- a/src/insexpand.c
+++ b/src/insexpand.c
@@ -3537,11 +3537,41 @@
     int		in_fuzzy = ((get_cot_flags() & COT_FUZZY) != 0 && leader_len > 0);
     char_u	**sorted_matches;
     int		*fuzzy_indices_data;
+    char_u	*last_sep = NULL;
+    size_t	path_with_wildcard_len;
+    char_u	*path_with_wildcard;
 
     if (in_fuzzy)
     {
-	vim_free(compl_pattern);
-	compl_pattern = vim_strsave((char_u *)"*");
+	last_sep = vim_strrchr(leader, PATHSEP);
+	if (last_sep == NULL)
+	{
+	    // No path separator or separator is the last character,
+	    // fuzzy match the whole leader
+	    vim_free(compl_pattern);
+	    compl_pattern = vim_strsave((char_u *)"*");
+	    compl_patternlen = STRLEN(compl_pattern);
+	}
+	else if (*(last_sep + 1) == '\0')
+	    in_fuzzy = FALSE;
+	else
+	{
+	    // Split leader into path and file parts
+	    int path_len = last_sep - leader + 1;
+	    path_with_wildcard_len = path_len + 2;
+	    path_with_wildcard = alloc(path_with_wildcard_len);
+	    if (path_with_wildcard != NULL)
+	    {
+		vim_strncpy(path_with_wildcard, leader, path_len);
+		vim_strcat(path_with_wildcard, (char_u *)"*", path_with_wildcard_len);
+		vim_free(compl_pattern);
+		compl_pattern = path_with_wildcard;
+		compl_patternlen = STRLEN(compl_pattern);
+
+		// Move leader to the file part
+		leader = last_sep + 1;
+	    }
+	}
     }
 
     if (expand_wildcards(1, &compl_pattern, &num_matches, &matches,
diff --git a/src/search.c b/src/search.c
index f7aab7b..c8f8736 100644
--- a/src/search.c
+++ b/src/search.c
@@ -5222,15 +5222,16 @@
     if (whole_line)
 	current_pos.lnum += dir;
 
+    if (buf == curbuf)
+        circly_end = *start_pos;
+    else
+    {
+        circly_end.lnum = buf->b_ml.ml_line_count;
+        circly_end.col = 0;
+        circly_end.coladd = 0;
+    }
+
     do {
-	if (buf == curbuf)
-	    circly_end = *start_pos;
-	else
-	{
-	    circly_end.lnum = buf->b_ml.ml_line_count;
-	    circly_end.col = 0;
-	    circly_end.coladd = 0;
-	}
 
 	// Check if looped around and back to start position
 	if (looped_around && EQUAL_POS(current_pos, circly_end))
@@ -5255,6 +5256,8 @@
 			*pos = current_pos;
 			break;
 		    }
+		    else if (looped_around && current_pos.lnum == circly_end.lnum)
+			break;
 		}
 		else
 		{
diff --git a/src/testdir/test_ins_complete.vim b/src/testdir/test_ins_complete.vim
index e9f9c9e..f3f6eac 100644
--- a/src/testdir/test_ins_complete.vim
+++ b/src/testdir/test_ins_complete.vim
@@ -2625,6 +2625,10 @@
   call assert_equal('fobar', getline('.'))
   call feedkeys("Sfob\<C-X>\<C-f>\<C-N>\<Esc>0", 'tx!')
   call assert_equal('foobar', getline('.'))
+  call feedkeys("S../\<C-X>\<C-f>\<Esc>0", 'tx!')
+  call assert_match('../*', getline('.'))
+  call feedkeys("S../td\<C-X>\<C-f>\<Esc>0", 'tx!')
+  call assert_match('../testdir', getline('.'))
 
   " can get completion from other buffer
   set completeopt=fuzzy,menu,menuone
@@ -2639,6 +2643,8 @@
   call assert_equal('Omnipotent', getline('.'))
   call feedkeys("Somp\<C-P>\<C-P>\<Esc>0", 'tx!')
   call assert_equal('Composite', getline('.'))
+  call feedkeys("S omp\<C-N>\<Esc>0", 'tx!')
+  call assert_equal(' completeness', getline('.'))
 
   " fuzzy on whole line completion
   call setline(1, ["world is on fire", "no one can save me but you", 'user can execute', ''])
diff --git a/src/version.c b/src/version.c
index e00d6c8..a04e7b8 100644
--- a/src/version.c
+++ b/src/version.c
@@ -705,6 +705,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    605,
+/**/
     604,
 /**/
     603,