Skip to content

Commit

Permalink
GenIdea: Improved Scala 3 Support (#1486)
Browse files Browse the repository at this point in the history
Implement `language-level` property for Scala library in IntelliJ IDEA.

Pull request: #1486
  • Loading branch information
lefou authored Sep 24, 2021
1 parent 4f91313 commit 5266b79
Show file tree
Hide file tree
Showing 11 changed files with 130 additions and 74 deletions.
4 changes: 2 additions & 2 deletions main/core/src/eval/Evaluator.scala
Original file line number Diff line number Diff line change
Expand Up @@ -664,10 +664,10 @@ object Evaluator {
rawValues: Seq[Result[Any]],
evaluated: Agg[Task[_]],
transitive: Agg[Task[_]],
failing: MultiBiMap[Either[Task[_], Labelled[_]], Result.Failing[_]],
failing: MultiBiMap[Either[Task[_], Labelled[_]], mill.api.Result.Failing[_]],
results: collection.Map[Task[_], Result[Any]]
) {
def values = rawValues.collect { case Result.Success(v) => v }
def values = rawValues.collect { case mill.api.Result.Success(v) => v }
}

def plan(rootModule: BaseModule, goals: Agg[Task[_]]) = {
Expand Down
111 changes: 68 additions & 43 deletions scalalib/src/GenIdeaImpl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import ammonite.runtime.SpecialClassLoader
import coursier.core.compatibility.xmlParseDom
import coursier.maven.Pom
import coursier.{LocalRepositories, Repositories, Repository}
import mill.Agg
import mill.api.Ctx.{Home, Log}
import mill.api.Strict.Agg
import mill.api.{Loose, PathRef, Result, Strict}
import mill.api.{PathRef, Result, Strict}
import mill.define._
import mill.eval.Evaluator
import mill.modules.Util
Expand Down Expand Up @@ -149,7 +149,7 @@ case class GenIdeaImpl(
case x: ScalaModule => x.scalaCompilerClasspath
case _ =>
T.task {
Loose.Agg.empty[PathRef]
Agg.empty[PathRef]
}
}

Expand All @@ -169,14 +169,13 @@ case class GenIdeaImpl(
}

val (scalacPluginsIvyDeps, allScalacOptions) = mod match {
case mod: ScalaModule =>
T.task {
mod.scalacPluginIvyDeps()
} -> T.task {
mod.allScalacOptions()
}
case _ => T.task(Loose.Agg[Dep]()) -> T.task(Seq())
case mod: ScalaModule => (
T.task(mod.scalacPluginIvyDeps()),
T.task(mod.allScalacOptions())
)
case _ => (T.task { Agg[Dep]() }, T.task { Seq() })
}

val scalacPluginDependencies = T.task {
mod.resolveDeps(scalacPluginsIvyDeps)()
}
Expand All @@ -194,19 +193,19 @@ case class GenIdeaImpl(
}

T.task {
val resolvedCp: Loose.Agg[Scoped[Path]] =
val resolvedCp: Agg[Scoped[Path]] =
externalDependencies().map(_.path).map(Scoped(_, None)) ++
extCompileIvyDeps()
.map(_.path)
.map(Scoped(_, Some("PROVIDED"))) ++
extRunIvyDeps().map(_.path).map(Scoped(_, Some("RUNTIME")))
// unused, but we want to trigger sources, to have them available (automatically)
// TODO: make this a separate eval to handle resolve errors
val resolvedSrcs: Loose.Agg[PathRef] = externalSources()
val resolvedSp: Loose.Agg[PathRef] = scalacPluginDependencies()
val resolvedCompilerCp: Loose.Agg[PathRef] =
val resolvedSrcs: Agg[PathRef] = externalSources()
val resolvedSp: Agg[PathRef] = scalacPluginDependencies()
val resolvedCompilerCp: Agg[PathRef] =
scalaCompilerClasspath()
val resolvedLibraryCp: Loose.Agg[PathRef] =
val resolvedLibraryCp: Agg[PathRef] =
externalLibraryDependencies()
val scalacOpts: Seq[String] = allScalacOptions()
val resolvedFacets: Seq[JavaFacet] = facets()
Expand All @@ -232,22 +231,23 @@ case class GenIdeaImpl(
}
}

val resolved: Seq[ResolvedModule] =
val resolvedModules: Seq[ResolvedModule] =
evalOrElse(evaluator, T.sequence(resolveTasks), Seq())

val moduleLabels = modules.map(_.swap).toMap

val allResolved: Seq[Path] =
(resolved.flatMap(_.classpath).map(_.value) ++ buildLibraryPaths ++ buildDepsPaths)
(resolvedModules.flatMap(_.classpath).map(_.value) ++ buildLibraryPaths ++ buildDepsPaths)
.distinct
.sorted

val librariesProperties = resolved
.flatMap(x => x.libraryClasspath.map(_ -> x.compilerClasspath))
.toMap
val librariesProperties: Map[Path, Agg[Path]] =
resolvedModules
.flatMap(x => x.libraryClasspath.map(_ -> x.compilerClasspath))
.toMap

val (wholeFileConfigs, configFileContributions) =
resolved
resolvedModules
.flatMap(_.configFileContributions)
.partition(_.asWholeFile.isDefined)

Expand Down Expand Up @@ -308,8 +308,14 @@ case class GenIdeaImpl(
.groupBy(_.last)
.filter(_._2.size > 1)
.view
.mapValues(_.sorted)
.mapValues(_.zipWithIndex)
.flatMap(y => y._2.map(x => x._1 -> s"${y._1} (${x._2})"))
.flatMap(y =>
y._2.map {
case (path, 0) => path -> y._1
case (path, idx) => path -> s"${y._1} (${idx})"
}
)
.toMap

val pathToLibName = allResolved
Expand Down Expand Up @@ -408,8 +414,8 @@ case class GenIdeaImpl(
.map(toResolvedJar)
.collect { case Some(r) => r }

val compilerSettings = resolved
.foldLeft(Map[(Loose.Agg[os.Path], Seq[String]), Vector[JavaModule]]()) {
val compilerSettings = resolvedModules
.foldLeft(Map[(Agg[os.Path], Seq[String]), Vector[JavaModule]]()) {
(r, q) =>
val key = (q.pluginClasspath, q.scalaOptions)
r + (key -> (r.getOrElse(key, Vector()) :+ q.module))
Expand Down Expand Up @@ -443,27 +449,40 @@ case class GenIdeaImpl(

val libraries: Seq[(SubPath, Elem)] =
resolvedLibraries(allResolved).flatMap { resolved =>
import resolved.path
val names = libraryNames(resolved)
val sources = resolved match {
case CoursierResolved(_, _, s) => s
case WithSourcesResolved(_, s) => s
case OtherResolved(_) => None
}
for (name <- names)
yield Tuple2(
os.sub / "libraries" / s"${ideaifyLibraryName(name)}.xml",
libraryXmlTemplate(
name = name,
path = path,
sources = sources,
scalaCompilerClassPath =
librariesProperties.getOrElse(path, Loose.Agg.empty)
yield {
val compilerCp: Agg[Path] = librariesProperties.getOrElse(resolved.path, Agg.empty)
val languageLevel = name match {
case _ if compilerCp.iterator.isEmpty => None
case _ if name.startsWith("scala3-library_3-3.0.") => Some("Scala_3_0")
case _ if name.startsWith("scala-library-2.13.") => Some("Scala_2_13")
case _ if name.startsWith("scala-library-2.12.") => Some("Scala_2_12")
case _ if name.startsWith("scala-library-2.11.") => Some("Scala_2_11")
case _ if name.startsWith("scala-library-2.10.") => Some("Scala_2_10")
case _ if name.startsWith("scala-library-2.9.") => Some("Scala_2_9")
case _ if name.startsWith("dotty-library-0.27") => Some("Scala_0_27")
case _ => None
}
Tuple2(
os.sub / "libraries" / s"${ideaifyLibraryName(name)}.xml",
libraryXmlTemplate(
name = name,
path = resolved.path,
sources = sources,
scalaCompilerClassPath = compilerCp,
languageLevel = languageLevel
)
)
)
}
}

val moduleFiles: Seq[(SubPath, Elem)] = resolved.map {
val moduleFiles: Seq[(SubPath, Elem)] = resolvedModules.map {
case ResolvedModule(
path,
resolvedDeps,
Expand Down Expand Up @@ -704,17 +723,23 @@ case class GenIdeaImpl(
name: String,
path: os.Path,
sources: Option[os.Path],
scalaCompilerClassPath: Loose.Agg[Path]
scalaCompilerClassPath: Agg[Path],
languageLevel: Option[String]
): Elem = {
val isScalaLibrary = scalaCompilerClassPath.iterator.nonEmpty
<component name="libraryTable">
<library name={name} type={if (isScalaLibrary) "Scala" else null}>
{
if (isScalaLibrary) {
<properties>
<compiler-classpath>
{
if (languageLevel.isDefined) <language-level>{languageLevel.get}</language-level>
}
<compiler-classpath>
{
scalaCompilerClassPath.toList.sortBy(_.wrapped).map(p => <root url={relativeFileUrl(p)}/>)
scalaCompilerClassPath.iterator.toSeq.sortBy(_.wrapped).map(p =>
<root url={relativeFileUrl(p)}/>
)
}
</compiler-classpath>
</properties>
Expand Down Expand Up @@ -820,7 +845,7 @@ case class GenIdeaImpl(
</module>
}
def scalaCompilerTemplate(
settings: Map[(Loose.Agg[os.Path], Seq[String]), Seq[JavaModule]]
settings: Map[(Agg[os.Path], Seq[String]), Seq[JavaModule]]
) = {

<project version={"" + ideaConfigVersion}>
Expand Down Expand Up @@ -904,12 +929,12 @@ object GenIdeaImpl {

final case class ResolvedModule(
path: Segments,
classpath: Loose.Agg[Scoped[Path]],
classpath: Agg[Scoped[Path]],
module: JavaModule,
pluginClasspath: Loose.Agg[Path],
pluginClasspath: Agg[Path],
scalaOptions: Seq[String],
compilerClasspath: Loose.Agg[Path],
libraryClasspath: Loose.Agg[Path],
compilerClasspath: Agg[Path],
libraryClasspath: Agg[Path],
facets: Seq[JavaFacet],
configFileContributions: Seq[IdeaConfigFile],
compilerOutput: Path
Expand Down
10 changes: 7 additions & 3 deletions scalalib/test/resources/gen-idea-extended-hello-world/build.sc
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,15 @@ import mill.scalalib.GenIdeaModule._
import mill.scalalib.TestModule

trait HelloWorldModule extends scalalib.ScalaModule {
def scalaVersion = "2.12.4"
override def scalaVersion = "2.13.6"
object test extends super.Tests with TestModule.Utest

def generatedSources = T {
Seq(PathRef(T.ctx().dest / "classes"))
override def generatedSources = T {
Seq(PathRef(T.dest / "classes"))
}

object subScala3 extends scalalib.ScalaModule {
override def scalaVersion = "3.0.2"
}

def ideaJavaModuleFacets(ideaConfigVersion: Int): Command[Seq[JavaFacet]] =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
<component name="libraryTable">
<library name="scala-library-2.12.4.jar" type="Scala">
<library name="scala-library-2.13.6.jar" type="Scala">
<properties>
<language-level>Scala_2_13</language-level>
<compiler-classpath>
<root url="file://COURSIER_HOME/https/repo1.maven.org/maven2/org/scala-lang/modules/scala-xml_2.12/1.0.6/scala-xml_2.12-1.0.6.jar"/>
<root url="file://COURSIER_HOME/https/repo1.maven.org/maven2/org/scala-lang/scala-compiler/2.12.4/scala-compiler-2.12.4.jar"/>
<root url="file://COURSIER_HOME/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.12.4/scala-library-2.12.4.jar"/>
<root url="file://COURSIER_HOME/https/repo1.maven.org/maven2/org/scala-lang/scala-reflect/2.12.4/scala-reflect-2.12.4.jar"/>
<root url="file://COURSIER_HOME/https/repo1.maven.org/maven2/net/java/dev/jna/jna/5.3.1/jna-5.3.1.jar"/>
<root url="file://COURSIER_HOME/https/repo1.maven.org/maven2/org/jline/jline/3.19.0/jline-3.19.0.jar"/>
<root url="file://COURSIER_HOME/https/repo1.maven.org/maven2/org/scala-lang/scala-compiler/2.13.6/scala-compiler-2.13.6.jar"/>
<root url="file://COURSIER_HOME/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.6/scala-library-2.13.6.jar"/>
<root url="file://COURSIER_HOME/https/repo1.maven.org/maven2/org/scala-lang/scala-reflect/2.13.6/scala-reflect-2.13.6.jar"/>
</compiler-classpath>
</properties>
<CLASSES>
<root url="jar://COURSIER_HOME/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.12.4/scala-library-2.12.4.jar!/"/>
<root url="jar://COURSIER_HOME/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.6/scala-library-2.13.6.jar!/"/>
</CLASSES>
<SOURCES>
<root url="jar://COURSIER_HOME/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.12.4/scala-library-2.12.4-sources.jar!/"/>
<root url="jar://COURSIER_HOME/https/repo1.maven.org/maven2/org/scala-lang/scala-library/2.13.6/scala-library-2.13.6-sources.jar!/"/>
</SOURCES>
</library>
</component>
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
</content>
<orderEntry type="inheritedJdk"/>
<orderEntry type="sourceFolder" forTests="false"/>
<orderEntry type="library" name="scala-library-2.12.4.jar" level="project"/>
<orderEntry type="library" name="scala-library-2.13.6.jar" level="project"/>
</component>
<component name="FacetManager">
<facet type="AspectJ" name="AspectJ">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager">
<output url="file://$MODULE_DIR$/../../out/HelloWorld/subScala3/ideaCompileOutput/dest/classes"/>
<exclude-output/>
<content url="file://$MODULE_DIR$/../../HelloWorld/subScala3/src">
<sourceFolder url="file://$MODULE_DIR$/../../HelloWorld/subScala3/src" isTestSource="false"/>
</content>
<content url="file://$MODULE_DIR$/../../HelloWorld/subScala3/resources">
<sourceFolder url="file://$MODULE_DIR$/../../HelloWorld/subScala3/resources" type="java-resource"/>
</content>
<orderEntry type="inheritedJdk"/>
<orderEntry type="sourceFolder" forTests="false"/>
<orderEntry type="library" name="scala-library-2.13.6.jar" level="project"/>
<orderEntry type="library" name="scala3-library_3-3.0.2.jar" level="project"/>
</component>
</module>
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</content>
<orderEntry type="inheritedJdk"/>
<orderEntry type="sourceFolder" forTests="false"/>
<orderEntry type="library" name="scala-library-2.12.4.jar" level="project"/>
<orderEntry type="library" name="scala-library-2.13.6.jar" level="project"/>
<orderEntry type="module" module-name="helloworld" exported=""/>
</component>
</module>
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/mill_modules/mill-build.iml" filepath="$PROJECT_DIR$/.idea/mill_modules/mill-build.iml"/>
<module fileurl="file://$PROJECT_DIR$/.idea/mill_modules/helloworld.iml" filepath="$PROJECT_DIR$/.idea/mill_modules/helloworld.iml"/>
<module fileurl="file://$PROJECT_DIR$/.idea/mill_modules/helloworld.subscala3.iml" filepath="$PROJECT_DIR$/.idea/mill_modules/helloworld.subscala3.iml"/>
<module fileurl="file://$PROJECT_DIR$/.idea/mill_modules/helloworld.test.iml" filepath="$PROJECT_DIR$/.idea/mill_modules/helloworld.test.iml"/>
</modules>
</component>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<component name="libraryTable">
<library name="scala-library-2.12.4.jar" type="Scala">
<properties>
<language-level>Scala_2_12</language-level>
<compiler-classpath>
<root url="file://COURSIER_HOME/https/repo1.maven.org/maven2/org/scala-lang/modules/scala-xml_2.12/1.0.6/scala-xml_2.12-1.0.6.jar"/>
<root url="file://COURSIER_HOME/https/repo1.maven.org/maven2/org/scala-lang/scala-compiler/2.12.4/scala-compiler-2.12.4.jar"/>
Expand Down
24 changes: 14 additions & 10 deletions scalalib/test/src/GenIdeaExtendedTests.scala
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package mill.scalalib

import scala.util.Try

import mill.util.ScriptTestSuite
import os.Path
import utest._
Expand All @@ -16,24 +18,26 @@ object GenIdeaExtendedTests extends ScriptTestSuite(false) {
val workspacePath = initWorkspace()
eval("mill.scalalib.GenIdea/idea")

Seq(
val checks = Seq(
os.sub / "mill_modules" / "helloworld.iml",
os.sub / "mill_modules" / "helloworld.test.iml",
os.sub / "mill_modules" / "helloworld.subscala3.iml",
os.sub / "mill_modules" / "mill-build.iml",
os.sub / "libraries" / "scala_library_2_12_4_jar.xml",
os.sub / "libraries" / "scala_library_2_13_6_jar.xml",
os.sub / "modules.xml",
os.sub / "misc.xml",
os.sub / "compiler.xml"
).foreach { resource =>
GenIdeaTests.assertIdeaXmlResourceMatchesFile(
workspaceSlug,
workspacePath,
resource
)
).map { resource =>
Try {
GenIdeaTests.assertIdeaXmlResourceMatchesFile(
workspaceSlug,
workspacePath,
resource
)
}
}
assert(checks.forall(_.isSuccess))
}
}



}
Loading

0 comments on commit 5266b79

Please sign in to comment.