Skip to content

Commit dc73372

Browse files
committed
feat: add fuzzy matching algorithm for tab completions
Signed-off-by: Snehil Shah <[email protected]>
1 parent cace7bf commit dc73372

File tree

1 file changed

+68
-1
lines changed

1 file changed

+68
-1
lines changed

lib/node_modules/@stdlib/repl/lib/filter_by_prefix.js

+68-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,73 @@
2121
// MODULES //
2222

2323
var startsWith = require( '@stdlib/string/starts-with' );
24+
var max = require( '@stdlib/math/base/special/max' );
25+
var abs = require( '@stdlib/math/base/special/abs' );
26+
27+
28+
// FUNCTIONS //
29+
30+
/**
31+
* Checks if the completion is a fuzzy match for the input.
32+
*
33+
* A fuzzy match is determined by the number and order of matching characters, penalizing large distances between matches.
34+
* A score above or equal to 0.8 indicates a match.
35+
*
36+
* @private
37+
* @param {string} completion - The completion string.
38+
* @param {string} input - The input string.
39+
* @returns {boolean} - True if the completion is a fuzzy match for the input, false otherwise.
40+
*/
41+
function fuzzyMatch( completion, input ) {
42+
var charPositions;
43+
var finalScore;
44+
var positions;
45+
var distance;
46+
var score;
47+
var index;
48+
var char;
49+
var i;
50+
var j;
51+
52+
if ( startsWith( completion, input ) ) {
53+
return true; // Return true for perfect matches
54+
}
55+
56+
// Preprocess the completion string to get the positions of each character
57+
positions = {};
58+
for ( i = 0; i < completion.length; i++ ) {
59+
char = completion[ i ];
60+
if (!positions[ char ]) {
61+
positions[ char] = [];
62+
}
63+
positions[ char ].push( i );
64+
}
65+
66+
score = 0;
67+
index = 0;
68+
for ( i = 0; i < input.length; i++ ) {
69+
charPositions = positions[ input[ i ] ];
70+
if ( !charPositions ) {
71+
continue;
72+
}
73+
74+
// Find the next position of the character that is greater than or equal to index
75+
j = 0;
76+
while ( j < charPositions.length && charPositions[ j ] < index ) {
77+
j += 1;
78+
}
79+
if ( j === charPositions.length ) {
80+
continue;
81+
}
82+
83+
distance = abs( charPositions[ j ] - i );
84+
score += max( 0, 1 - ( distance * 0.25 ) ); // Subtract a penalty based on the distance between matching characters
85+
index = charPositions[ j ] + 1;
86+
}
87+
finalScore = score / input.length; // Calculate relative score
88+
89+
return finalScore >= 0.65;
90+
}
2491

2592

2693
// MAIN //
@@ -37,7 +104,7 @@ var startsWith = require( '@stdlib/string/starts-with' );
37104
function filterByPrefix( out, arr, str ) {
38105
var i;
39106
for ( i = 0; i < arr.length; i++ ) {
40-
if ( startsWith( arr[ i ], str ) ) {
107+
if ( fuzzyMatch( arr[ i ], str ) ) {
41108
out.push( arr[ i ] );
42109
}
43110
}

0 commit comments

Comments
 (0)