ENSIME support #2075
Replies: 3 comments 11 replies
-
If all you need to support ENSIME from Mill is the use of a scalac compiler plugin, that it should be easy to add. A solution that can work without any changes to Mill itself could be a custom We had some comparable support for Metals to provide semanticDB data, before we provided built-in support for semanticDB. Have a look at the now deprecated trait A trivial implementation could look as follows: trait EnsimeSupport extends ScalaModule {
override def scalacPluginIvyDeps: Target[Agg[Dep]] = T {
super.scalacPluginIvyDeps() ++ Agg(
ivy"..." // the Maven or Ivy GAV of your plugin
)
} Of course, you can make that much more sophisticated. If your plugin is not consumable via Maven/Ivy, you need to add it to You would use it as follows: object foo extends ScalaModule with EnsimeSupport {
// ...
} I also recommend to read the various discussions that led to the current built-in design, esp. to understand why we don't support some side-injections of scalac options. |
Beta Was this translation helpful? Give feedback.
-
Can you describe, how your compiler plugin and your editing experience works? How are dependencies handled? How do you support cross-setups where alternative source files for the same final class exists? |
Beta Was this translation helpful? Give feedback.
-
Project-level plugin. It would be great to see this added to the core Mill distribution so that ENSIME users don't have to do anything. The check at val ensimeWanted = os.exists(os.home / ".cache" / "ensime") can be safely, and quickly, used to enable/disable all the logic. import mill._
import mill.scalalib._
// To install this Mill plugin, add
//
// ```
// import $file.plugins.Ensime
// import Ensime.EnsimeModule
//
// object ... extends EnsimeModule
// ```
//
// to your build.sc
trait EnsimeModule extends ScalaModule { module =>
def ensimeJar : T[Option[PathRef]] = T.input {
val jar = os.home / ".cache" / "ensime" / "lib" / s"""ensime-${scalaVersion()}.jar"""
val ensimeWanted = os.exists(os.home / ".cache" / "ensime")
if (os.isFile(jar) && ensimeWanted) {
// make sure the user always has sources if ENSIME is enabled
val fetchTask = fetchDepSources()
fetchTask()
Some(PathRef(jar))
} else {
if (ensimeWanted){
T.ctx.log.error(s"ENSIME not found. Try\n\n sbt ++${scalaVersion()}! install\n\nin the ensime-tng repo.")
}
None
}
}
override def scalacOptions = T {
super.scalacOptions() ++ {ensimeJar() match {
case Some(jar) => Seq(s"-Xplugin:${jar.path.toIO.getAbsolutePath}")
case None => Seq()
}}
}
private def fetchDepSources: mill.define.Task[() => Unit] = T.task {
import coursier._
import coursier.util._
import scala.concurrent.ExecutionContext.Implicits.global
val repos = module.repositoriesTask()
val allIvyDeps = module.transitiveIvyDeps() ++ module.transitiveCompileIvyDeps()
val coursierDeps = allIvyDeps.map(module.resolveCoursierDependency()).toList
val withSources = Resolution(
coursierDeps
.map(d =>
d.withAttributes(
d.attributes.withClassifier(coursier.Classifier("sources"))
)
)
.toSeq
)
() => {
val fetch = ResolutionProcess.fetch(repos, coursier.cache.Cache.default.fetch)
val _ = withSources.process.run(fetch).unsafeRun()
}
}
} |
Beta Was this translation helpful? Give feedback.
-
Quite a few people have asked if they could use ENSIME on projects that are built with Mill, so I'm interested in finding out what needs to be done to make that happen.
Ideally the user could install a plugin that is automatically included by every Mill build, which adds
to the scalac options for every file that is built in the project.
However, I don't believe Mill has the concept of a globally installed user plugin, like sbt has, so it might be worth exploring adding support for that to Mill itself. The support would be inert by default. e.g.
do you have any ideas on how to do it without requiring changes to Mill itself?
Beta Was this translation helpful? Give feedback.
All reactions