@@ -204,7 +204,18 @@ jobs:
204204
205205impl Creator {
206206 fn new ( options : NewOptions , gleam_version : & ' static str ) -> Result < Self , Error > {
207- let project_name = get_valid_project_name ( options. name . clone ( ) , & options. project_root ) ?;
207+ Self :: new_with_confirmation ( options, gleam_version, crate :: cli:: confirm)
208+ }
209+
210+ fn new_with_confirmation (
211+ mut options : NewOptions ,
212+ gleam_version : & ' static str ,
213+ confirm : impl Fn ( & str ) -> Result < bool , Error > ,
214+ ) -> Result < Self , Error > {
215+ let name =
216+ get_valid_project_name ( options. name . as_deref ( ) , & options. project_root , & confirm) ?;
217+ options. project_root = name. project_root ( & options. project_root ) ;
218+
208219 let root = get_current_directory ( ) ?. join ( & options. project_root ) ;
209220 let src = root. join ( "src" ) ;
210221 let test = root. join ( "test" ) ;
@@ -218,7 +229,7 @@ impl Creator {
218229 workflows,
219230 gleam_version,
220231 options,
221- project_name,
232+ project_name : name . decided ( ) . to_string ( ) ,
222233 } ;
223234
224235 validate_root_folder ( & me) ?;
@@ -406,16 +417,28 @@ fn suggest_valid_name(invalid_name: &str, reason: &InvalidProjectNameReason) ->
406417 }
407418}
408419
409- fn get_valid_project_name ( name : Option < String > , project_root : & str ) -> Result < String , Error > {
410- let initial_name = match name {
411- Some ( name) => name,
412- None => get_foldername ( project_root) ?,
413- }
414- . trim ( )
415- . to_string ( ) ;
420+ fn get_valid_project_name (
421+ provided_name : Option < & str > ,
422+ project_root : & str ,
423+ confirm : impl Fn ( & str ) -> Result < bool , Error > ,
424+ ) -> Result < ProjectName , Error > {
425+ let initial_name = match provided_name {
426+ Some ( name) => name. trim ( ) . to_string ( ) ,
427+ None => get_foldername ( project_root) ?. trim ( ) . to_string ( ) ,
428+ } ;
416429
417430 let invalid_reason = match validate_name ( & initial_name) {
418- Ok ( _) => return Ok ( initial_name) ,
431+ Ok ( _) => {
432+ return Ok ( match provided_name {
433+ Some ( _) => ProjectName :: Provided {
434+ decided : initial_name,
435+ } ,
436+ None => ProjectName :: Derived {
437+ folder : initial_name. clone ( ) ,
438+ decided : initial_name,
439+ } ,
440+ } ) ;
441+ }
419442 Err ( Error :: InvalidProjectName { reason, .. } ) => reason,
420443 Err ( error) => return Err ( error) ,
421444 } ;
@@ -429,18 +452,29 @@ fn get_valid_project_name(name: Option<String>, project_root: &str) -> Result<St
429452 } ) ;
430453 }
431454 } ;
455+
432456 let prompt_for_suggested_name = error:: format_invalid_project_name_error (
433457 & initial_name,
434458 & invalid_reason,
435459 & Some ( suggested_name. clone ( ) ) ,
436460 ) ;
437- match crate :: cli:: confirm ( & prompt_for_suggested_name) ? {
438- true => Ok ( suggested_name) ,
439- false => Err ( Error :: InvalidProjectName {
440- name : initial_name,
441- reason : invalid_reason,
442- } ) ,
461+
462+ if confirm ( & prompt_for_suggested_name) ? {
463+ return Ok ( match provided_name {
464+ Some ( _) => ProjectName :: Provided {
465+ decided : suggested_name,
466+ } ,
467+ None => ProjectName :: Derived {
468+ folder : initial_name,
469+ decided : suggested_name,
470+ } ,
471+ } ) ;
443472 }
473+
474+ Err ( Error :: InvalidProjectName {
475+ name : initial_name,
476+ reason : invalid_reason,
477+ } )
444478}
445479
446480fn get_foldername ( path : & str ) -> Result < String , Error > {
@@ -461,3 +495,37 @@ fn get_foldername(path: &str) -> Result<String, Error> {
461495 } ) ,
462496 }
463497}
498+
499+ #[ derive( Debug , Clone ) ]
500+ enum ProjectName {
501+ Provided { decided : String } ,
502+ Derived { folder : String , decided : String } ,
503+ }
504+
505+ impl ProjectName {
506+ fn decided ( & self ) -> & str {
507+ match self {
508+ Self :: Provided { decided } | Self :: Derived { decided, .. } => decided,
509+ }
510+ }
511+
512+ fn project_root ( & self , current_root : & str ) -> String {
513+ match self {
514+ Self :: Provided { .. } => current_root. to_string ( ) ,
515+ Self :: Derived { folder, decided } => {
516+ if current_root == "." || folder == decided {
517+ return current_root. to_string ( ) ;
518+ }
519+
520+ // If the name was invalid and generated suggestion was accepted,
521+ // align the directory path with the new name.
522+ let original_root = Utf8Path :: new ( current_root) ;
523+ let new_root = match original_root. parent ( ) {
524+ Some ( parent) if !parent. as_str ( ) . is_empty ( ) => parent. join ( decided) ,
525+ Some ( _) | None => Utf8PathBuf :: from ( decided) ,
526+ } ;
527+ new_root. to_string ( )
528+ }
529+ }
530+ }
531+ }
0 commit comments