Skip to content

Commit 5ec80a2

Browse files
abs0lutylpil
authored andcommitted
gleam new now creates the project directory using the confirmed project name
1 parent fe82f12 commit 5ec80a2

File tree

3 files changed

+121
-17
lines changed

3 files changed

+121
-17
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,10 @@
6767
version upgrades has been improved.
6868
([Louis Pilfold](https://github.com/lpil))
6969

70+
- `gleam new` now creates the project directory using the confirmed project
71+
name when a suggested rename is accepted.
72+
([Adi Salimgereyev](https://github.com/abs0luty))
73+
7074
### Language server
7175

7276
- The "inline variable" code action can now trigger when used over the let

compiler-cli/src/new.rs

Lines changed: 84 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,18 @@ jobs:
204204

205205
impl 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

446480
fn 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+
}

compiler-cli/src/new/tests.rs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use std::path::PathBuf;
22

3-
use camino::Utf8PathBuf;
3+
use camino::{Utf8Path, Utf8PathBuf};
44
use gleam_core::Error;
55

66
#[test]
@@ -337,6 +337,38 @@ fn skip_existing_git_files_when_skip_git_is_true() {
337337
assert!(path.join(".gitignore").exists());
338338
}
339339

340+
#[test]
341+
fn suggested_project_name_updates_directory() {
342+
let tmp = tempfile::tempdir().unwrap();
343+
let base = Utf8PathBuf::from_path_buf(tmp.path().to_path_buf()).expect("Non Utf8 Path");
344+
let original_root = base.join("gleam_testproject");
345+
346+
let creator = super::Creator::new_with_confirmation(
347+
super::NewOptions {
348+
project_root: original_root.to_string(),
349+
template: super::Template::Erlang,
350+
name: None,
351+
skip_git: true,
352+
skip_github: true,
353+
},
354+
"1.0.0-gleam",
355+
|_| Ok::<bool, Error>(true),
356+
)
357+
.unwrap();
358+
359+
let expected_root = base.join("testproject");
360+
assert_eq!(creator.project_name, "testproject");
361+
assert_eq!(
362+
Utf8Path::new(&creator.options.project_root),
363+
expected_root.as_path()
364+
);
365+
366+
creator.run().unwrap();
367+
368+
assert!(expected_root.exists());
369+
assert!(!original_root.exists());
370+
}
371+
340372
#[test]
341373
fn validate_name_format() {
342374
assert!(crate::new::validate_name("project").is_ok());

0 commit comments

Comments
 (0)