@@ -26,243 +26,6 @@ use super::skim::Movement::{Match, Skip};
2626use super :: util:: { char_equal, cheap_matches} ;
2727use super :: { FuzzyMatcher , IndexType , MatchIndices , ScoreType } ;
2828
29- const BONUS_MATCHED : ScoreType = 4 ;
30- const BONUS_CASE_MATCH : ScoreType = 4 ;
31- const BONUS_UPPER_MATCH : ScoreType = 6 ;
32- const BONUS_ADJACENCY : ScoreType = 10 ;
33- const BONUS_SEPARATOR : ScoreType = 8 ;
34- const BONUS_CAMEL : ScoreType = 8 ;
35- const PENALTY_CASE_UNMATCHED : ScoreType = -1 ;
36- const PENALTY_LEADING : ScoreType = -6 ;
37- // penalty applied for every letter before the first match
38- const PENALTY_MAX_LEADING : ScoreType = -18 ;
39- // maxing penalty for leading letters
40- const PENALTY_UNMATCHED : ScoreType = -2 ;
41-
42- #[ deprecated( since = "0.3.5" , note = "Please use SkimMatcherV2 instead" ) ]
43- /// Legacy fuzzy matcher (V1) - deprecated, use SkimMatcherV2 instead
44- #[ derive( Default , Debug ) ]
45- pub struct SkimMatcher { }
46-
47- /// The V1 matcher is based on ForrestTheWoods's post
48- /// https://www.forrestthewoods.com/blog/reverse_engineering_sublime_texts_fuzzy_match/
49- ///
50- /// V1 algorithm is deprecated, checkout `FuzzyMatcherV2`
51- impl FuzzyMatcher for SkimMatcher {
52- fn fuzzy_indices ( & self , choice : & str , pattern : & str ) -> Option < ( ScoreType , MatchIndices ) > {
53- fuzzy_indices ( choice, pattern) . map ( |( s, v) | ( s, MatchIndices :: from ( v) ) )
54- }
55-
56- fn fuzzy_match ( & self , choice : & str , pattern : & str ) -> Option < ScoreType > {
57- fuzzy_match ( choice, pattern)
58- }
59- }
60-
61- #[ deprecated( since = "0.3.5" , note = "Please use SkimMatcherV2 instead" ) ]
62- /// Legacy fuzzy matching function - returns match score only
63- pub fn fuzzy_match ( choice : & str , pattern : & str ) -> Option < ScoreType > {
64- if pattern. is_empty ( ) {
65- return Some ( 0 ) ;
66- }
67-
68- let scores = build_graph ( choice, pattern) ?;
69-
70- let last_row = & scores[ scores. len ( ) - 1 ] ;
71- let ( _, & MatchingStatus { final_score, .. } ) = last_row
72- . iter ( )
73- . enumerate ( )
74- . max_by_key ( |& ( _, x) | x. final_score )
75- . expect ( "fuzzy_indices failed to iterate over last_row" ) ;
76- Some ( final_score)
77- }
78-
79- #[ deprecated( since = "0.3.5" , note = "Please use SkimMatcherV2 instead" ) ]
80- /// Legacy fuzzy matching function - returns match score and character indices
81- pub fn fuzzy_indices ( choice : & str , pattern : & str ) -> Option < ( ScoreType , Vec < IndexType > ) > {
82- if pattern. is_empty ( ) {
83- return Some ( ( 0 , Vec :: new ( ) ) ) ;
84- }
85-
86- let mut picked = vec ! [ ] ;
87- let scores = build_graph ( choice, pattern) ?;
88-
89- let last_row = & scores[ scores. len ( ) - 1 ] ;
90- let ( mut next_col, & MatchingStatus { final_score, .. } ) = last_row
91- . iter ( )
92- . enumerate ( )
93- . max_by_key ( |& ( _, x) | x. final_score )
94- . expect ( "fuzzy_indices failed to iterate over last_row" ) ;
95- let mut pat_idx = scores. len ( ) as i64 - 1 ;
96- while pat_idx >= 0 {
97- let status = scores[ pat_idx as usize ] [ next_col] ;
98- next_col = status. back_ref as usize ;
99- picked. push ( status. idx ) ;
100- pat_idx -= 1 ;
101- }
102- picked. reverse ( ) ;
103- Some ( ( final_score, picked) )
104- }
105-
106- #[ derive( Clone , Copy , Debug ) ]
107- struct MatchingStatus {
108- pub idx : IndexType ,
109- pub score : ScoreType ,
110- pub final_score : ScoreType ,
111- pub adj_num : IndexType ,
112- pub back_ref : IndexType ,
113- }
114-
115- impl Default for MatchingStatus {
116- fn default ( ) -> Self {
117- MatchingStatus {
118- idx : 0 ,
119- score : 0 ,
120- final_score : 0 ,
121- adj_num : 1 ,
122- back_ref : 0 ,
123- }
124- }
125- }
126-
127- fn build_graph ( choice : & str , pattern : & str ) -> Option < Vec < Vec < MatchingStatus > > > {
128- let mut scores = vec ! [ ] ;
129-
130- let mut match_start_idx = 0 ; // to ensure that the pushed char are able to match the pattern
131- let mut pat_prev_ch = '\0' ;
132-
133- // initialize the match positions and inline scores
134- for ( pat_idx, pat_ch) in pattern. chars ( ) . enumerate ( ) {
135- let mut vec = vec ! [ ] ;
136- let mut choice_prev_ch = '\0' ;
137- for ( idx, ch) in choice. chars ( ) . enumerate ( ) {
138- if char_equal ( ch, pat_ch, false ) && idx >= match_start_idx {
139- let score = fuzzy_score (
140- ch,
141- idx as IndexType ,
142- choice_prev_ch,
143- pat_ch,
144- pat_idx as IndexType ,
145- pat_prev_ch,
146- ) ;
147- vec. push ( MatchingStatus {
148- idx : idx as IndexType ,
149- score,
150- final_score : score,
151- adj_num : 1 ,
152- back_ref : 0 ,
153- } ) ;
154- }
155- choice_prev_ch = ch;
156- }
157-
158- if vec. is_empty ( ) {
159- // not matched
160- return None ;
161- }
162- match_start_idx = vec[ 0 ] . idx + 1 ;
163- scores. push ( vec) ;
164- pat_prev_ch = pat_ch;
165- }
166-
167- // calculate max scores considering adjacent characters
168- for pat_idx in 1 ..scores. len ( ) {
169- let ( first_half, last_half) = scores. split_at_mut ( pat_idx) ;
170-
171- let prev_row = & first_half[ first_half. len ( ) - 1 ] ;
172- let cur_row = & mut last_half[ 0 ] ;
173-
174- for idx in 0 ..cur_row. len ( ) {
175- let next = cur_row[ idx] ;
176- let prev = if idx > 0 {
177- cur_row[ idx - 1 ]
178- } else {
179- MatchingStatus :: default ( )
180- } ;
181-
182- let mut score_before_idx = prev. final_score - prev. score + next. score ;
183- score_before_idx += PENALTY_UNMATCHED * ( ( next. idx - prev. idx ) as ScoreType ) ;
184- score_before_idx -= if prev. adj_num == 0 { BONUS_ADJACENCY } else { 0 } ;
185-
186- let ( back_ref, score, adj_num) = prev_row
187- . iter ( )
188- . enumerate ( )
189- . take_while ( |& ( _, & MatchingStatus { idx, .. } ) | idx < next. idx )
190- . skip_while ( |& ( _, & MatchingStatus { idx, .. } ) | idx < prev. idx )
191- . map ( |( back_ref, cur) | {
192- let adj_num = next. idx - cur. idx - 1 ;
193- let mut final_score = cur. final_score + next. score ;
194- final_score += if adj_num == 0 {
195- BONUS_ADJACENCY
196- } else {
197- PENALTY_UNMATCHED * adj_num as ScoreType
198- } ;
199- ( back_ref, final_score, adj_num)
200- } )
201- . max_by_key ( |& ( _, x, _) | x)
202- . unwrap_or ( ( prev. back_ref , score_before_idx, prev. adj_num ) ) ;
203-
204- cur_row[ idx] = if idx > 0 && score < score_before_idx {
205- MatchingStatus {
206- final_score : score_before_idx,
207- back_ref : prev. back_ref ,
208- adj_num,
209- ..next
210- }
211- } else {
212- MatchingStatus {
213- final_score : score,
214- back_ref : back_ref as IndexType ,
215- adj_num,
216- ..next
217- }
218- } ;
219- }
220- }
221-
222- Some ( scores)
223- }
224-
225- // judge how many scores the current index should get
226- fn fuzzy_score (
227- choice_ch : char ,
228- choice_idx : IndexType ,
229- choice_prev_ch : char ,
230- pat_ch : char ,
231- pat_idx : IndexType ,
232- _pat_prev_ch : char ,
233- ) -> ScoreType {
234- let mut score = BONUS_MATCHED ;
235-
236- let choice_prev_ch_type = CharType :: of ( choice_prev_ch) ;
237- let choice_role = CharRole :: of ( choice_prev_ch, choice_ch) ;
238-
239- if pat_ch == choice_ch {
240- if pat_ch. is_uppercase ( ) {
241- score += BONUS_UPPER_MATCH ;
242- } else {
243- score += BONUS_CASE_MATCH ;
244- }
245- } else {
246- score += PENALTY_CASE_UNMATCHED ;
247- }
248-
249- // apply bonus for camelCases
250- if choice_role == CharRole :: Head || choice_role == CharRole :: Break || choice_role == CharRole :: Camel {
251- score += BONUS_CAMEL ;
252- }
253-
254- // apply bonus for matches after a separator
255- if choice_prev_ch_type == CharType :: HardSep || choice_prev_ch_type == CharType :: SoftSep {
256- score += BONUS_SEPARATOR ;
257- }
258-
259- if pat_idx == 0 {
260- score += max ( ( choice_idx as ScoreType ) * PENALTY_LEADING , PENALTY_MAX_LEADING ) ;
261- }
262-
263- score
264- }
265-
26629#[ derive( Copy , Clone , Debug ) ]
26730/// Configuration for skim's scoring algorithm
26831pub struct SkimScoreConfig {
@@ -520,9 +283,6 @@ enum CharRole {
520283}
521284
522285impl CharRole {
523- pub fn of ( prev : char , cur : char ) -> Self {
524- Self :: of_type ( CharType :: of ( prev) , CharType :: of ( cur) )
525- }
526286 pub fn of_type ( prev : CharType , cur : CharType ) -> Self {
527287 match ( prev, cur) {
528288 ( CharType :: Empty , _) | ( CharType :: HardSep , _) => CharRole :: Head ,
0 commit comments