Skip to content

Commit

Permalink
Fixing the new project wizard
Browse files Browse the repository at this point in the history
  • Loading branch information
hmemcpy committed Oct 19, 2024
1 parent 986fe35 commit 6df086b
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 110 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)
Expand All @@ -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
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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._
Expand Down Expand Up @@ -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 {
Expand All @@ -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
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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)))

}
Original file line number Diff line number Diff line change
Expand Up @@ -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._
Expand All @@ -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,
Expand All @@ -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 = {
Expand Down Expand Up @@ -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"),
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -271,5 +213,6 @@ final class ZioNewProjectWizardStep(parent: ScalaNewProjectWizardStep)
}
}

// TODO support onboarding tips
override private[project] def setGenerateOnboardingTips(value: lang.Boolean): Unit = ()
}
2 changes: 1 addition & 1 deletion src/main/scala/zio/intellij/utils/ZioVersion.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
}

0 comments on commit 6df086b

Please sign in to comment.