From 20fd9f4b9648c58569d5b3d03a0e26a84d93e4a1 Mon Sep 17 00:00:00 2001 From: Dmitry Bushev Date: Tue, 6 Dec 2022 20:43:33 +0300 Subject: [PATCH] Ensure project name starts with uppercase (#3947) Fixes the regression when IDE fails to create a project from template. Project name should start with an upper case letter to pass the server side validation. --- .../double-representation/src/name/project.rs | 97 +++++++++++++++++++ app/gui/src/controller/ide.rs | 3 +- app/gui/src/controller/ide/desktop.rs | 23 +++-- app/gui/src/presenter.rs | 29 +++--- 4 files changed, 133 insertions(+), 19 deletions(-) diff --git a/app/gui/controller/double-representation/src/name/project.rs b/app/gui/controller/double-representation/src/name/project.rs index ea3b006d21..c19e598285 100644 --- a/app/gui/controller/double-representation/src/name/project.rs +++ b/app/gui/controller/double-representation/src/name/project.rs @@ -28,6 +28,103 @@ pub const STANDARD_BASE_LIBRARY_PATH: &str = concatcp!(STANDARD_NAMESPACE, ".", +// ================ +// === Template === +// ================ + +#[allow(missing_docs)] +#[derive(Copy, Clone, Debug, Fail)] +pub enum InvalidTemplateName { + #[fail(display = "The template name contains invalid characters.")] + ContainsInvalidCharacters, +} + +/// The project template name. +#[derive(Clone, Debug)] +pub struct Template { + name: String, +} + +impl Template { + /// Create the project template from string. + /// + /// # Example + /// + /// ```rust + /// # use double_representation::name::project::Template; + /// assert!(Template::from_text("hello").is_ok()); + /// assert!(Template::from_text("hello_world").is_err()); + /// ``` + pub fn from_text(text: impl AsRef) -> FallibleResult { + if text.as_ref().contains(|c: char| !c.is_ascii_alphanumeric()) { + Err(InvalidTemplateName::ContainsInvalidCharacters.into()) + } else { + Ok(Template { name: text.as_ref().to_owned() }) + } + } + + /// Create the project template from string without validation. + pub fn unsafe_from_text(text: impl AsRef) -> Self { + Template { name: text.as_ref().to_owned() } + } + + /// Create a project name from the template name. + /// # Example + /// + /// ```rust + /// # use double_representation::name::project::Template; + /// let template = Template::unsafe_from_text("hello"); + /// assert_eq!(template.to_project_name(), "Hello".to_owned()); + /// ``` + pub fn to_project_name(&self) -> String { + let mut name = self.name.to_string(); + // Capitalize + if let Some(r) = name.get_mut(0..1) { + r.make_ascii_uppercase(); + } + + name + } +} + +// === Conversions From and Into String === + +impl TryFrom<&str> for Template { + type Error = failure::Error; + + fn try_from(text: &str) -> Result { + Self::from_text(text) + } +} + +impl TryFrom for Template { + type Error = failure::Error; + + fn try_from(text: String) -> Result { + Self::from_text(text) + } +} + +impl From