@@ -203,6 +203,8 @@ static int compl_opt_suppress_empty = FALSE;
203203
204204static int compl_selected_item = -1 ;
205205
206+ static int * compl_fuzzy_scores ;
207+
206208static int ins_compl_add (char_u * str , int len , char_u * fname , char_u * * cptext , typval_T * user_data , int cdir , int flags , int adup );
207209static void ins_compl_longest_match (compl_T * match );
208210static void ins_compl_del_pum (void );
@@ -3322,7 +3324,8 @@ typedef struct
33223324process_next_cpt_value (
33233325 ins_compl_next_state_T * st ,
33243326 int * compl_type_arg ,
3325- pos_T * start_match_pos )
3327+ pos_T * start_match_pos ,
3328+ int in_fuzzy )
33263329{
33273330 int compl_type = -1 ;
33283331 int status = INS_COMPL_CPT_OK ;
@@ -3338,7 +3341,7 @@ process_next_cpt_value(
33383341 st -> first_match_pos = * start_match_pos ;
33393342 // Move the cursor back one character so that ^N can match the
33403343 // word immediately after the cursor.
3341- if (ctrl_x_mode_normal () && dec (& st -> first_match_pos ) < 0 )
3344+ if (ctrl_x_mode_normal () && (! in_fuzzy && dec (& st -> first_match_pos ) < 0 ) )
33423345 {
33433346 // Move the cursor to after the last character in the
33443347 // buffer, so that word at start of buffer is found
@@ -3505,6 +3508,18 @@ get_next_tag_completion(void)
35053508 p_ic = save_p_ic ;
35063509}
35073510
3511+ /*
3512+ * Compare function for qsort
3513+ */
3514+ static int compare_scores (const void * a , const void * b )
3515+ {
3516+ int idx_a = * (const int * )a ;
3517+ int idx_b = * (const int * )b ;
3518+ int score_a = compl_fuzzy_scores [idx_a ];
3519+ int score_b = compl_fuzzy_scores [idx_b ];
3520+ return (score_a > score_b ) ? -1 : (score_a < score_b ) ? 1 : 0 ;
3521+ }
3522+
35083523/*
35093524 * Get the next set of filename matching "compl_pattern".
35103525 */
@@ -3513,6 +3528,21 @@ get_next_filename_completion(void)
35133528{
35143529 char_u * * matches ;
35153530 int num_matches ;
3531+ char_u * ptr ;
3532+ garray_T fuzzy_indices ;
3533+ int i ;
3534+ int score ;
3535+ char_u * leader = ins_compl_leader ();
3536+ int leader_len = STRLEN (leader );
3537+ int in_fuzzy = ((get_cot_flags () & COT_FUZZY ) != 0 && leader_len > 0 );
3538+ char_u * * sorted_matches ;
3539+ int * fuzzy_indices_data ;
3540+
3541+ if (in_fuzzy )
3542+ {
3543+ vim_free (compl_pattern );
3544+ compl_pattern = vim_strsave ((char_u * )"*" );
3545+ }
35163546
35173547 if (expand_wildcards (1 , & compl_pattern , & num_matches , & matches ,
35183548 EW_FILE |EW_DIR |EW_ADDSLASH |EW_SILENT ) != OK )
@@ -3523,12 +3553,9 @@ get_next_filename_completion(void)
35233553#ifdef BACKSLASH_IN_FILENAME
35243554 if (curbuf -> b_p_csl [0 ] != NUL )
35253555 {
3526- int i ;
3527-
35283556 for (i = 0 ; i < num_matches ; ++ i )
35293557 {
3530- char_u * ptr = matches [i ];
3531-
3558+ ptr = matches [i ];
35323559 while (* ptr != NUL )
35333560 {
35343561 if (curbuf -> b_p_csl [0 ] == 's' && * ptr == '\\' )
@@ -3540,6 +3567,41 @@ get_next_filename_completion(void)
35403567 }
35413568 }
35423569#endif
3570+
3571+ if (in_fuzzy )
3572+ {
3573+ ga_init2 (& fuzzy_indices , sizeof (int ), 10 );
3574+ compl_fuzzy_scores = (int * )alloc (sizeof (int ) * num_matches );
3575+
3576+ for (i = 0 ; i < num_matches ; i ++ )
3577+ {
3578+ ptr = matches [i ];
3579+ score = fuzzy_match_str (ptr , leader );
3580+ if (score > 0 )
3581+ {
3582+ if (ga_grow (& fuzzy_indices , 1 ) == OK )
3583+ {
3584+ ((int * )fuzzy_indices .ga_data )[fuzzy_indices .ga_len ] = i ;
3585+ compl_fuzzy_scores [i ] = score ;
3586+ fuzzy_indices .ga_len ++ ;
3587+ }
3588+ }
3589+ }
3590+
3591+ fuzzy_indices_data = (int * )fuzzy_indices .ga_data ;
3592+ qsort (fuzzy_indices_data , fuzzy_indices .ga_len , sizeof (int ), compare_scores );
3593+
3594+ sorted_matches = (char_u * * )alloc (sizeof (char_u * ) * fuzzy_indices .ga_len );
3595+ for (i = 0 ; i < fuzzy_indices .ga_len ; ++ i )
3596+ sorted_matches [i ] = vim_strsave (matches [fuzzy_indices_data [i ]]);
3597+
3598+ FreeWild (num_matches , matches );
3599+ matches = sorted_matches ;
3600+ num_matches = fuzzy_indices .ga_len ;
3601+ vim_free (compl_fuzzy_scores );
3602+ ga_clear (& fuzzy_indices );
3603+ }
3604+
35433605 ins_compl_add_matches (num_matches , matches , p_fic || p_wic );
35443606}
35453607
@@ -3687,8 +3749,10 @@ get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_pos)
36873749 int save_p_scs ;
36883750 int save_p_ws ;
36893751 int looped_around = FALSE;
3690- char_u * ptr ;
3691- int len ;
3752+ char_u * ptr = NULL ;
3753+ int len = 0 ;
3754+ int in_fuzzy = (get_cot_flags () & COT_FUZZY ) != 0 && compl_length > 0 ;
3755+ char_u * leader = ins_compl_leader ();
36923756
36933757 // If 'infercase' is set, don't use 'smartcase' here
36943758 save_p_scs = p_scs ;
@@ -3702,7 +3766,7 @@ get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_pos)
37023766 save_p_ws = p_ws ;
37033767 if (st -> ins_buf != curbuf )
37043768 p_ws = FALSE;
3705- else if (* st -> e_cpt == '.' )
3769+ else if (* st -> e_cpt == '.' && ! in_fuzzy )
37063770 p_ws = TRUE;
37073771 looped_around = FALSE;
37083772 for (;;)
@@ -3713,9 +3777,13 @@ get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_pos)
37133777
37143778 // ctrl_x_mode_line_or_eval() || word-wise search that
37153779 // has added a word that was at the beginning of the line
3716- if (ctrl_x_mode_line_or_eval () || (compl_cont_status & CONT_SOL ))
3780+ if (( ctrl_x_mode_whole_line () && ! in_fuzzy ) || ctrl_x_mode_eval () || (compl_cont_status & CONT_SOL ))
37173781 found_new_match = search_for_exact_line (st -> ins_buf ,
37183782 st -> cur_match_pos , compl_direction , compl_pattern );
3783+ else if (in_fuzzy )
3784+ found_new_match = search_for_fuzzy_match (st -> ins_buf ,
3785+ st -> cur_match_pos , leader , compl_direction ,
3786+ start_pos , & len , & ptr , ctrl_x_mode_whole_line ());
37193787 else
37203788 found_new_match = searchit (NULL , st -> ins_buf , st -> cur_match_pos ,
37213789 NULL , compl_direction , compl_pattern , compl_patternlen ,
@@ -3764,8 +3832,9 @@ get_next_default_completion(ins_compl_next_state_T *st, pos_T *start_pos)
37643832 && start_pos -> col == st -> cur_match_pos -> col )
37653833 continue ;
37663834
3767- ptr = ins_compl_get_next_word_or_line (st -> ins_buf , st -> cur_match_pos ,
3768- & len , & cont_s_ipos );
3835+ if (!in_fuzzy )
3836+ ptr = ins_compl_get_next_word_or_line (st -> ins_buf , st -> cur_match_pos ,
3837+ & len , & cont_s_ipos );
37693838 if (ptr == NULL )
37703839 continue ;
37713840
@@ -3864,6 +3933,7 @@ ins_compl_get_exp(pos_T *ini)
38643933 int i ;
38653934 int found_new_match ;
38663935 int type = ctrl_x_mode ;
3936+ int in_fuzzy = (get_cot_flags () & COT_FUZZY ) != 0 ;
38673937
38683938 if (!compl_started )
38693939 {
@@ -3889,8 +3959,11 @@ ins_compl_get_exp(pos_T *ini)
38893959 st .ins_buf = curbuf ; // In case the buffer was wiped out.
38903960
38913961 compl_old_match = compl_curr_match ; // remember the last current match
3892- st .cur_match_pos = (compl_dir_forward ())
3893- ? & st .last_match_pos : & st .first_match_pos ;
3962+ if (in_fuzzy )
3963+ st .cur_match_pos = (compl_dir_forward ())
3964+ ? & st .last_match_pos : & st .first_match_pos ;
3965+ else
3966+ st .cur_match_pos = & st .last_match_pos ;
38943967
38953968 // For ^N/^P loop over all the flags/windows/buffers in 'complete'.
38963969 for (;;)
@@ -3904,7 +3977,7 @@ ins_compl_get_exp(pos_T *ini)
39043977 if ((ctrl_x_mode_normal () || ctrl_x_mode_line_or_eval ())
39053978 && (!compl_started || st .found_all ))
39063979 {
3907- int status = process_next_cpt_value (& st , & type , ini );
3980+ int status = process_next_cpt_value (& st , & type , ini , in_fuzzy );
39083981
39093982 if (status == INS_COMPL_CPT_END )
39103983 break ;
0 commit comments