@@ -29,6 +29,7 @@ use crate::core::Summary;
29
29
use crate :: core:: Workspace ;
30
30
use crate :: sources:: source:: QueryKind ;
31
31
use crate :: util:: cache_lock:: CacheLockMode ;
32
+ use crate :: util:: edit_distance;
32
33
use crate :: util:: style;
33
34
use crate :: util:: toml:: lookup_path_base;
34
35
use crate :: util:: toml_mut:: dependency:: Dependency ;
@@ -168,6 +169,33 @@ pub fn add(workspace: &Workspace<'_>, options: &AddOptions<'_>) -> CargoResult<(
168
169
write ! ( message, "no features available for crate {}" , dep. name) ?;
169
170
} else {
170
171
if !deactivated. is_empty ( ) {
172
+ let mut suggested_features = Vec :: new ( ) ;
173
+ for unknown_feature in & unknown_features {
174
+ if let Some ( suggested_feature) =
175
+ edit_distance:: closest ( unknown_feature, deactivated. iter ( ) , |dep| * dep)
176
+ {
177
+ suggested_features. push ( suggested_feature) ;
178
+ }
179
+ }
180
+ if ( 1 ..=MAX_FEATURE_PRINTS ) . contains ( & suggested_features. len ( ) ) {
181
+ writeln ! (
182
+ message,
183
+ "help: similarly named feature{suffix1} exist{suffix2}:{newline} {suggestions}" ,
184
+ suffix1 = if suggested_features. len( ) == 1 { "" } else { "s" } ,
185
+ suffix2 = if suggested_features. len( ) == 1 { "s" } else { "" } ,
186
+ newline = if suggested_features. len( ) == 1 { "" } else { "\n " } ,
187
+ suggestions = suggested_features
188
+ . into_iter( )
189
+ . map( |s| s. to_string( ) )
190
+ . coalesce( |x, y| if x. len( ) + y. len( ) < 78 {
191
+ Ok ( format!( "{x}, {y}" ) )
192
+ } else {
193
+ Err ( ( x, y) )
194
+ } )
195
+ . into_iter( )
196
+ . format( "\n " )
197
+ ) ?;
198
+ }
171
199
if deactivated. len ( ) <= MAX_FEATURE_PRINTS {
172
200
writeln ! (
173
201
message,
0 commit comments