@@ -1307,6 +1307,28 @@ mod tests {
13071307 }
13081308 }
13091309
1310+ #[ test]
1311+ fn unknown_argument_suggests_with_many_unrelated_keys ( ) {
1312+ let mut parser = ArgumentParser :: new ( "app" )
1313+ . with_argument ( Argument :: new ( "--port" ) . with_type ( ArgumentType :: Integer ) ) ;
1314+ for i in 0 ..500 {
1315+ let long_name = Box :: leak (
1316+ format ! ( "--very-long-unrelated-argument-name-{}" , i) . into_boxed_str ( ) ,
1317+ ) ;
1318+ parser = parser. with_argument (
1319+ Argument :: new ( long_name) . with_type ( ArgumentType :: String ) ,
1320+ ) ;
1321+ }
1322+
1323+ let err = parser. parse ( & argv ( & [ "--portt" , "1" ] ) ) . unwrap_err ( ) ;
1324+ match err {
1325+ ArgsError :: UnknownArgument ( msg) => {
1326+ assert ! ( msg. contains( "did you mean '--port'" ) )
1327+ }
1328+ _ => panic ! ( ) ,
1329+ }
1330+ }
1331+
13101332 #[ test]
13111333 fn missing_value_error ( ) {
13121334 let parser = ArgumentParser :: new ( "app" )
@@ -1512,7 +1534,16 @@ fn read_config_file(
15121534
15131535fn unknown_with_suggestion ( arg : & str , parser : & ArgumentParser ) -> String {
15141536 let mut best: Option < ( usize , String ) > = None ;
1537+ let arg_len = arg. chars ( ) . count ( ) ;
15151538 for key in parser. args . keys ( ) {
1539+ // Levenshtein distance has a hard lower bound of the character-length gap.
1540+ // If that bound cannot beat the current best score, skip this candidate.
1541+ if let Some ( ( best_distance, _) ) = best. as_ref ( ) {
1542+ let key_len = key. chars ( ) . count ( ) ;
1543+ if key_len. abs_diff ( arg_len) >= * best_distance {
1544+ continue ;
1545+ }
1546+ }
15161547 let d = levenshtein ( arg, key) ;
15171548 if best. as_ref ( ) . map ( |( bd, _) | d < * bd) . unwrap_or ( true ) {
15181549 best = Some ( ( d, key. clone ( ) ) ) ;
0 commit comments