diff --git a/src/main/scala/zio/intellij/project/npw/template/wizard/ZioModuleStepLike.scala b/src/main/scala/zio/intellij/project/npw/template/wizard/ZioModuleStepLike.scala index 0aa1453..3cb7659 100644 --- a/src/main/scala/zio/intellij/project/npw/template/wizard/ZioModuleStepLike.scala +++ b/src/main/scala/zio/intellij/project/npw/template/wizard/ZioModuleStepLike.scala @@ -4,15 +4,19 @@ package org.jetbrains.sbt.project.template.wizard import com.intellij.openapi.Disposable import com.intellij.openapi.progress.ProgressIndicator import com.intellij.ui.components.JBCheckBox +import com.intellij.ui.dsl.builder.{Panel, Row, RowLayout} +import com.intellij.ui.dsl.gridLayout.HorizontalAlign +import kotlin.Unit.{INSTANCE => KUnit} import org.jetbrains.plugins.scala.ScalaVersion -import org.jetbrains.plugins.scala.extensions.{applyTo, ObjectExt} +import org.jetbrains.plugins.scala.extensions.{ObjectExt, applyTo} import org.jetbrains.plugins.scala.project.Versions import org.jetbrains.sbt.project.template.SComboBox import zio.intellij.ZioIcon -import zio.intellij.utils.{DownloadUtil, ZioVersion} +import zio.intellij.utils.DownloadUtil import java.util.concurrent.atomic.{AtomicBoolean, AtomicReference} import javax.swing.JLabel +import scala.annotation.nowarn import scala.collection.immutable.ListSet trait ZioModuleStepLike extends SbtModuleStepLike { @@ -24,12 +28,16 @@ trait ZioModuleStepLike extends SbtModuleStepLike { private val isZioVersionManuallySelected: AtomicBoolean = new AtomicBoolean(false) - private val isZioLoading = new AtomicBoolean(false) + // + // Raw UI elements + // - protected lazy val zioVersionComboBox: SComboBox[String] = + private val isZioLoading = new AtomicBoolean(false) + private lazy val zioVersionComboBox: SComboBox[String] = createSComboBoxWithSearchingListRenderer(ListSet(defaultAvailableZioVersions.versions: _*), None, isZioLoading) - private def downloadAvailableVersions(disposable: Disposable): Unit = { + + private def downloadZioVersions(disposable: Disposable): Unit = { val zioDownloadVersions: ProgressIndicator => Versions = indicator => { val scalaVersion = selections.scalaVersion.flatMap(ScalaVersion.fromString).getOrElse(ScalaVersion.Latest.Scala_2_13) @@ -54,16 +62,40 @@ trait ZioModuleStepLike extends SbtModuleStepLike { label.setIcon(ZioIcon) label.setDisplayedMnemonic('Z') label + } + protected def setUpZioUI(panel: Panel) = { + panel.row( + zioLabel, + (row: Row) => { + row.layout(RowLayout.PARENT_GRID) + row.cell(zioVersionComboBox).horizontalAlign(HorizontalAlign.FILL): @nowarn("cat=deprecation") + row.cell(includeZioTestCheckbox) + KUnit + } + ) } protected val includeZioTestCheckbox: JBCheckBox = applyTo(new JBCheckBox("Include 'zio-test'"))( - _.setToolTipText("Includes the ZIO Test library and configuration") + _.setToolTipText("Includes the ZIO Test library and configuration"), + _.setSelected(true) ) override def initSelectionsAndUi(contextDisposable: Disposable): Unit = { super.initSelectionsAndUi(contextDisposable) - includeZioTestCheckbox.setSelected(true) - downloadAvailableVersions(contextDisposable) + _initSelectionsAndUi + downloadZioVersions(contextDisposable) + } + + private lazy val _initSelectionsAndUi: Unit = { + initUiElementsListeners() } + + private def initUiElementsListeners() = { + zioVersionComboBox.addActionListener { _ => + isZioVersionManuallySelected.set(true) + selectedZioVersion = zioVersionComboBox.getSelectedItemTyped + } + } + } diff --git a/src/main/scala/zio/intellij/project/npw/template/wizard/ZioProjectBuilder.scala b/src/main/scala/zio/intellij/project/npw/template/wizard/ZioProjectBuilder.scala index 8388725..fea7534 100644 --- a/src/main/scala/zio/intellij/project/npw/template/wizard/ZioProjectBuilder.scala +++ b/src/main/scala/zio/intellij/project/npw/template/wizard/ZioProjectBuilder.scala @@ -2,6 +2,7 @@ package zio.intellij.project.npw.template.wizard import com.intellij.openapi.module.{ModifiableModuleModel, Module} import com.intellij.openapi.util.io +import com.intellij.openapi.util.io.FileUtilRt import org.jetbrains.annotations.NonNls import org.jetbrains.plugins.scala.ScalaVersion import org.jetbrains.plugins.scala.extensions._ @@ -35,7 +36,7 @@ final class ZioProjectBuilder(_selections: ZioProjectBuilder.Selections) extends packagePrefix ) = selections val sbtVersion = sbtVersionOpt.getOrElse(Versions.SBT.LatestSbtVersion) - val scalaVersion = scalaVersionOpt.getOrElse(ScalaVersion.Latest.Scala_2_13.minor) + val scalaVersion = scalaVersionOpt.getOrElse(ScalaVersion.Latest.Scala_3_3.minor) val zioVersion = zioVersionOpt.getOrElse(ZIO.`2.x.latest`.toString) locally { @@ -61,6 +62,18 @@ final class ZioProjectBuilder(_selections: ZioProjectBuilder.Selections) extends super.createModule(moduleModel) } + // TODO copied over from the Scala plugin: + // + // TODO customize the path in UI when IDEA-122951 will be implemented + /** + * By default module file points to the `projectRoot/moduleName.iml`. + * We replace ("re-point") it to `projectRoot/.idea/modules/moduleName.iml` + */ + private def moduleFilePathUpdated(pathname: String): String = { + val file = new File(pathname) + FileUtilRt.toSystemIndependentName(file.getParent) + "/" + Sbt.ModulesDirectory + "/" + file.getName + } + override def getNodeIcon: Icon = ZioIcon } diff --git a/src/main/scala/zio/intellij/project/npw/template/wizard/ZioProjectWizard.scala b/src/main/scala/zio/intellij/project/npw/template/wizard/ZioProjectWizard.scala index 01f6516..990c82c 100644 --- a/src/main/scala/zio/intellij/project/npw/template/wizard/ZioProjectWizard.scala +++ b/src/main/scala/zio/intellij/project/npw/template/wizard/ZioProjectWizard.scala @@ -3,7 +3,7 @@ package zio.intellij.project.npw.template.wizard import com.intellij.ide.util.projectWizard.WizardContext import com.intellij.ide.wizard._ import org.jetbrains.plugins.scala.util.ui.KotlinDslWrappers.StepChainOps -import org.jetbrains.sbt.project.template.wizard.ScalaNewProjectWizardStep +import org.jetbrains.sbt.project.template.wizard.ScalaNewProjectWizardMultiStep import org.jetbrains.sbt.project.template.wizard.buildSystem.ZioNewProjectWizardStep import zio.intellij.ZioIcon @@ -24,7 +24,7 @@ object ZioProjectWizard extends GeneratorNewProjectWizard { override def createStep(wizardContext: WizardContext): NewProjectWizardStep = new RootNewProjectWizardStep(wizardContext) .nextStep(new NewProjectWizardBaseStep(_)) - .nextStep(new NewProjectWizardLanguageStep(_, "Scala")) - .nextStep(parent => new ZioNewProjectWizardStep(new ScalaNewProjectWizardStep(parent))) + .nextStep(new NewProjectWizardLanguageStep(_, "Scala")) // Required to trick the wizard into thinking it's a Scala project (provides `LanguageNewProjectWizardData`) + .nextStep(parent => new ZioNewProjectWizardStep(new ScalaNewProjectWizardMultiStep(parent))) } diff --git a/src/main/scala/zio/intellij/project/npw/template/wizard/buildSystem/ZioNewProjectWizardStep.scala b/src/main/scala/zio/intellij/project/npw/template/wizard/buildSystem/ZioNewProjectWizardStep.scala index 7973fdc..54350a2 100644 --- a/src/main/scala/zio/intellij/project/npw/template/wizard/buildSystem/ZioNewProjectWizardStep.scala +++ b/src/main/scala/zio/intellij/project/npw/template/wizard/buildSystem/ZioNewProjectWizardStep.scala @@ -3,18 +3,14 @@ package org.jetbrains.sbt.project.template.wizard.buildSystem import com.intellij.ide.JavaUiBundle import com.intellij.ide.projectWizard.NewProjectWizardCollector.BuildSystem.{INSTANCE => BSLog} -import com.intellij.ide.wizard.AbstractNewProjectWizardStep -import com.intellij.openapi.GitRepositoryInitializer -import com.intellij.openapi.externalSystem.model.ExternalSystemDataKeys -import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl import com.intellij.openapi.module.{ModuleManager, StdModuleTypes} -import com.intellij.openapi.observable.properties.{GraphProperty, ObservableProperty, PropertyGraph} -import com.intellij.openapi.observable.util.BindUtil +import com.intellij.openapi.observable.properties.GraphProperty import com.intellij.openapi.project.Project import com.intellij.openapi.projectRoots.impl.DependentSdkType import com.intellij.openapi.projectRoots.{JavaSdkType, Sdk, SdkTypeId} import com.intellij.openapi.roots.ui.configuration.{JdkComboBox, ProjectStructureConfigurable} import com.intellij.openapi.ui.ValidationInfo +import com.intellij.openapi.vfs.VirtualFile import com.intellij.ui.UIBundle import com.intellij.ui.components.JBTextField import com.intellij.ui.dsl.builder._ @@ -25,79 +21,64 @@ import org.jetbrains.annotations.TestOnly import org.jetbrains.plugins.scala.extensions.{ObjectExt, ToNullSafe} import org.jetbrains.plugins.scala.project.Versions import org.jetbrains.plugins.scala.util.ui.extensions.JComboBoxOps -import org.jetbrains.sbt.project.template.SbtModuleBuilderSelections import org.jetbrains.sbt.project.template.wizard.kotlin_interop.{ComboBoxKt_Wrapper, JdkComboBoxKt_Interop} -import org.jetbrains.sbt.project.template.wizard.{ScalaNewProjectWizardStep, ZioModuleStepLike} +import org.jetbrains.sbt.project.template.wizard.{ScalaNewProjectWizardMultiStep, ZioModuleStepLike} +import org.jetbrains.sbt.project.template.{ModuleBuilderBase, SbtModuleBuilderSelections} import zio.intellij.project.npw.template.wizard.ZioProjectBuilder import zio.intellij.utils.ZioVersion import zio.intellij.utils.ZioVersion.ZIO import java.lang +import java.nio.file.Path import javax.swing.JLabel import scala.annotation.nowarn -// copied from SbtScalaNewProjectWizardStep +// copied from ZioNewProjectWizardStep, because it's final and cannot be modified //noinspection ApiStatus,UnstableApiUsage -final class ZioNewProjectWizardStep(parent: ScalaNewProjectWizardStep) - extends AbstractNewProjectWizardStep(parent) +final class ZioNewProjectWizardStep(parent: ScalaNewProjectWizardMultiStep) + extends ScalaNewProjectWizardStep(parent) with SbtScalaNewProjectWizardData with ScalaGitNewProjectWizardData with ScalaSampleCodeNewProjectWizardData with ZioModuleStepLike { - @inline private def propertyGraph: PropertyGraph = getPropertyGraph + private var sdkComboBox: Cell[JdkComboBox] = _ + private val sdkProperty: GraphProperty[Sdk] = propertyGraph.property(null) - private var sdkComboBox: Cell[JdkComboBox] = _ - private val sdkProperty: GraphProperty[Sdk] = propertyGraph.property(null) - private val moduleNameProperty: GraphProperty[String] = propertyGraph.lazyProperty(() => parent.getName) - - private val addSampleCodeProperty: GraphProperty[java.lang.Boolean] = propertyGraph.property(java.lang.Boolean.FALSE) - BindUtil.bindBooleanStorage(addSampleCodeProperty, "NewProjectWizard.addSampleCodeState") @TestOnly override private[project] def setAddSampleCode(value: java.lang.Boolean): Unit = addSampleCodeProperty.set(value) - private def needToAddSampleCode: Boolean = addSampleCodeProperty.get() - private val gitProperty: GraphProperty[java.lang.Boolean] = propertyGraph.property(java.lang.Boolean.FALSE) - BindUtil.bindBooleanStorage(gitProperty, "NewProjectWizard.gitState") @TestOnly override private[project] def setGit(value: java.lang.Boolean): Unit = gitProperty.set(value) - private def isGitRepository: Boolean = - Option(GitRepositoryInitializer.getInstance()).isDefined && gitProperty.get() - - @TestOnly override private[project] def setScalaVersion(version: String): Unit = - scalaVersionComboBox.setSelectedItemEnsuring(version) + @TestOnly override def setScalaVersion(version: String): Unit = scalaVersionComboBox.setSelectedItemEnsuring(version) @TestOnly override private[project] def setSbtVersion(version: String): Unit = sbtVersionComboBox.setSelectedItemEnsuring(version) @TestOnly override private[project] def setPackagePrefix(prefix: String): Unit = packagePrefixTextField.setText(prefix) - def getSdk: Sdk = sdkProperty.get() - def getModuleName: String = moduleNameProperty.get() + override def getSdk: Option[Sdk] = Option(sdkProperty.get()) override protected val selections: SbtModuleBuilderSelections = SbtModuleBuilderSelections.default override protected var selectedZioVersion: Option[String] = None - override protected lazy val defaultAvailableScalaVersions: Versions = Versions.Scala.allHardcodedVersions - override protected lazy val defaultAvailableSbtVersions: Versions = Versions.SBT.allHardcodedVersions + override protected lazy val defaultAvailableSbtVersions: Versions = Versions.SBT.allHardcodedVersions override protected lazy val defaultAvailableSbtVersionsForScala3: Versions = Versions.SBT.sbtVersionsForScala3(defaultAvailableSbtVersions) override protected lazy val defaultAvailableZioVersions: Versions = - Versions(ZIO.`2.x.latest`.toString, ZIO.`2.x.latest`.toString :: ZIO.`1.x.latest`.toString :: Nil) - - locally { - moduleNameProperty.dependsOn( - parent.getNameProperty: ObservableProperty[String], - (() => parent.getName): kotlin.jvm.functions.Function0[_ <: String] + Versions( + defaultVersion = ZIO.`2.x.latest`.toString, + versions = ZIO.`2.x.latest`.toString :: ZIO.`1.x.latest`.toString :: Nil ) + locally { getData.putUserData(SbtScalaNewProjectWizardData.KEY, this) getData.putUserData(ScalaGitNewProjectWizardData.KEY, this) getData.putUserData(ScalaSampleCodeNewProjectWizardData.KEY, this) } - override def setupProject(project: Project): Unit = { + override def createBuilder(): ModuleBuilderBase[_] = { val zioVersion = ZioVersion.parseUnsafe(selectedZioVersion.getOrElse(ZIO.`2.x.latest`.toString)) - val builder = new ZioProjectBuilder( + new ZioProjectBuilder( ZioProjectBuilder.Selections( sbtVersion = selections.sbtVersion, scalaVersion = selections.scalaVersion, @@ -109,25 +90,12 @@ final class ZioNewProjectWizardStep(parent: ScalaNewProjectWizardStep) packagePrefix = selections.packagePrefix ) ) - builder.setName(getModuleName) - val projectRoot = getContext.getProjectDirectory.toAbsolutePath - builder.setContentEntryPath(projectRoot.toString) - - setProjectOrModuleSdk(project, parent, builder, Option(getSdk)) - - ExternalProjectsManagerImpl.setupCreatedProject(project) - - /** - * NEWLY_CREATED_PROJECT must be set up to prevent the call of markDirtyAllExternalProjects in ExternalProjectsDataStorage#load. - * As a result, NEWLY_IMPORTED_PROJECT must also be set to keep the same behaviour as before in ExternalSystemStartupActivity.kt:48 (do not call ExternalSystemUtil#refreshProjects). - * Similar thing is done in AbstractGradleModuleBuilder#setupModule - */ - project.putUserData(ExternalSystemDataKeys.NEWLY_CREATED_PROJECT, java.lang.Boolean.TRUE) - project.putUserData(ExternalSystemDataKeys.NEWLY_IMPORTED_PROJECT, java.lang.Boolean.TRUE) - - if (isGitRepository) addGitIgnore(project, projectRoot.toString) + } - builder.commit(project) + override protected def _addScalaSampleCode(project: Project, projectRoot: Path): Seq[VirtualFile] = { + // TODO migrate to the new Sample Code templates (with rendered onboarding tips) + // For now, this is handled (*sigh* hardcoded) in the ZioProjectBuilder + Seq.empty } override def setupUI(panel: Panel): Unit = { @@ -162,51 +130,13 @@ final class ZioNewProjectWizardStep(parent: ScalaNewProjectWizardStep) } ) - panel.row( - scalaLabelText, - (row: Row) => { - row.layout(RowLayout.PARENT_GRID) - row.cell(scalaVersionComboBox).horizontalAlign(HorizontalAlign.FILL): @nowarn("cat=deprecation") - row.cell(downloadScalaSourcesCheckbox) - KUnit - } - ) + setUpScalaUI(panel, downloadSourcesCheckbox = true) - panel.row( - zioLabel, - (row: Row) => { - row.layout(RowLayout.PARENT_GRID) - row.cell(zioVersionComboBox).horizontalAlign(HorizontalAlign.FILL): @nowarn("cat=deprecation") - row.cell(includeZioTestCheckbox) - KUnit - } - ) + setUpZioUI(panel) setupPackagePrefixUI(panel) - panel - .row( - null: JLabel, - (row: Row) => { - val cb = row.checkBox("""Create a "Hello World" main app""") - ButtonKt.bindSelected( - cb, - addSampleCodeProperty: com.intellij.openapi.observable.properties.ObservableMutableProperty[ - java.lang.Boolean - ] - ) - ButtonKt.whenStateChangedFromUi( - cb, - null, - value => { - BSLog.logAddSampleCodeChanged(parent, value): @nowarn("cat=deprecation") - KUnit - } - ) - KUnit - } - ) - .topGap(TopGap.SMALL) + setUpSampleCode(panel) panel.collapsibleGroup( UIBundle.message("label.project.wizard.new.project.advanced.settings"), @@ -239,6 +169,18 @@ final class ZioNewProjectWizardStep(parent: ScalaNewProjectWizardStep) initSelectionsAndUi(getContext.getDisposable) } + override protected def setUpSampleCode(panel: Panel): Unit = { + panel.row(null: JLabel, (row: Row) => { + val cb = row.checkBox("""Create a "Hello World" main app""") + ButtonKt.bindSelected(cb, addSampleCodeProperty: com.intellij.openapi.observable.properties.ObservableMutableProperty[java.lang.Boolean]) + ButtonKt.whenStateChangedFromUi(cb, null, value => { + BSLog.logAddSampleCodeChanged(parent, value): @nowarn("cat=deprecation") + KUnit + }) + KUnit + }).topGap(TopGap.SMALL) + } + private def validateModuleName(builder: ValidationInfoBuilder, field: JBTextField): ValidationInfo = { val moduleName = field.getText val project = getContext.getProject @@ -271,5 +213,6 @@ final class ZioNewProjectWizardStep(parent: ScalaNewProjectWizardStep) } } + // TODO support onboarding tips override private[project] def setGenerateOnboardingTips(value: lang.Boolean): Unit = () } diff --git a/src/main/scala/zio/intellij/utils/ZioVersion.scala b/src/main/scala/zio/intellij/utils/ZioVersion.scala index a3f8c67..f3e5a4a 100644 --- a/src/main/scala/zio/intellij/utils/ZioVersion.scala +++ b/src/main/scala/zio/intellij/utils/ZioVersion.scala @@ -132,6 +132,6 @@ object ZioVersion { val `2.0.0-M2`: ZioVersion = ZioVersion.parseUnsafe("2.0.0-M2") // first version to support the built-in test runner val `2.0.0`: ZioVersion = ZioVersion.parseUnsafe("2.0.0") val `1.x.latest`: ZioVersion = ZioVersion.parseUnsafe("1.0.18") - val `2.x.latest`: ZioVersion = ZioVersion.parseUnsafe("2.1.1") + val `2.x.latest`: ZioVersion = ZioVersion.parseUnsafe("2.1.11") } }