patch 9.1.1046: fuzzymatching doesn't prefer matching camelcase

Problem:  fuzzymatching doesn't prefer matching camelcase
          (Tomasz N)
Solution: Add extra score when case matches (glepnir)

fixes: #16434
closes: #16439

Signed-off-by: glepnir <glephunter@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/search.c b/src/search.c
index 616331e..46fa7b9 100644
--- a/src/search.c
+++ b/src/search.c
@@ -42,7 +42,7 @@
 static int is_zero_width(char_u *pattern, size_t patternlen, int move, pos_T *cur, int direction);
 static void cmdline_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, int show_top_bot_msg, char_u *msgbuf, size_t msgbuflen, int recompute, int maxcount, long timeout);
 static void update_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, searchstat_T *stat, int recompute, int maxcount, long timeout);
-static int fuzzy_match_compute_score(char_u *str, int strSz, int_u *matches, int numMatches);
+static int fuzzy_match_compute_score(char_u *fuzpat, char_u *str, int strSz, int_u *matches, int numMatches);
 static int fuzzy_match_recursive(char_u *fuzpat, char_u *str, int_u strIdx, int *outScore, char_u *strBegin, int strLen, int_u *srcMatches, int_u *matches, int maxMatches, int nextMatch, int *recursionCount);
 #if defined(FEAT_EVAL) || defined(FEAT_PROTO)
 static int fuzzy_match_item_compare(const void *s1, const void *s2);
@@ -4355,6 +4355,10 @@
 #define CAMEL_BONUS 30
 // bonus if the first letter is matched
 #define FIRST_LETTER_BONUS 15
+// bonus if exact match
+#define EXACT_MATCH_BONUS 100
+// bonus if case match when no ignorecase
+#define CASE_MATCH_BONUS 25
 // penalty applied for every letter in str before the first match
 #define LEADING_LETTER_PENALTY (-5)
 // maximum penalty for leading letters
@@ -4374,6 +4378,7 @@
  */
     static int
 fuzzy_match_compute_score(
+	char_u		*fuzpat,
 	char_u		*str,
 	int		strSz,
 	int_u		*matches,
@@ -4386,6 +4391,11 @@
     char_u	*p = str;
     int_u	sidx = 0;
     int		is_exact_match = TRUE;
+    char_u	*orig_fuzpat = fuzpat - numMatches;
+    char_u	*curpat = orig_fuzpat;
+    int		pat_idx = 0;
+    // Track consecutive camel case matches
+    int		consecutive_camel = 0;
 
     // Initialize score
     score = 100;
@@ -4404,6 +4414,8 @@
     for (i = 0; i < numMatches; ++i)
     {
 	int_u	currIdx = matches[i];
+	int	curr;
+	int	is_camel = FALSE;
 
 	if (i > 0)
 	{
@@ -4413,15 +4425,18 @@
 	    if (currIdx == (prevIdx + 1))
 		score += SEQUENTIAL_BONUS;
 	    else
+	    {
 		score += GAP_PENALTY * (currIdx - prevIdx);
+		// Reset consecutive camel count on gap
+		consecutive_camel = 0;
+	    }
 	}
 
 	// Check for bonuses based on neighbor character value
 	if (currIdx > 0)
 	{
 	    // Camel case
-	    int	neighbor = ' ';
-	    int	curr;
+	    int neighbor = ' ';
 
 	    if (has_mbyte)
 	    {
@@ -4439,8 +4454,18 @@
 		curr = str[currIdx];
 	    }
 
+	    // Enhanced camel case scoring
 	    if (vim_islower(neighbor) && vim_isupper(curr))
-		score += CAMEL_BONUS;
+	    {
+		score += CAMEL_BONUS * 2;  // Double the camel case bonus
+		is_camel = TRUE;
+		consecutive_camel++;
+		// Additional bonus for consecutive camel
+		if (consecutive_camel > 1)
+		    score += CAMEL_BONUS;
+	    }
+	    else
+		consecutive_camel = 0;
 
 	    // Bonus if the match follows a separator character
 	    if (neighbor == '/' || neighbor == '\\')
@@ -4452,14 +4477,47 @@
 	{
 	    // First letter
 	    score += FIRST_LETTER_BONUS;
+	    curr = has_mbyte ? (*mb_ptr2char)(p) : str[currIdx];
 	}
+
+	// Case matching bonus
+	if (vim_isalpha(curr))
+	{
+	    while (pat_idx < i && *curpat)
+	    {
+		if (has_mbyte)
+		    MB_PTR_ADV(curpat);
+		else
+		    curpat++;
+		pat_idx++;
+	    }
+
+	    if (has_mbyte)
+	    {
+		if (curr == (*mb_ptr2char)(curpat))
+		{
+		    score += CASE_MATCH_BONUS;
+		    // Extra bonus for exact case match in camel
+		    if (is_camel)
+			score += CASE_MATCH_BONUS / 2;
+		}
+	    }
+	    else if (curr == *curpat)
+	    {
+		score += CASE_MATCH_BONUS;
+		if (is_camel)
+		    score += CASE_MATCH_BONUS / 2;
+	    }
+	}
+
 	// Check exact match condition
         if (currIdx != (int_u)i)
 	    is_exact_match = FALSE;
     }
+
     // Boost score for exact matches
     if (is_exact_match && numMatches == strSz)
-        score += 100;
+        score += EXACT_MATCH_BONUS;
 
     return score;
 }
@@ -4563,7 +4621,7 @@
 
     // Calculate score
     if (matched)
-	*outScore = fuzzy_match_compute_score(strBegin, strLen, matches,
+	*outScore = fuzzy_match_compute_score(fuzpat, strBegin, strLen, matches,
 		nextMatch);
 
     // Return best result