question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Is your feature request related to a problem? Please describe.

Some scala developers want to use ENSIME with scala-cli.

It seems in the best interests of the scala community that these tools are compatible with each other.

(I’m creating this ticket by proxy, I’m not a scala-cli user.)

Describe the solution you’d like

Ideally, the support would be automatic and baked in to the tool.

If the ensime jar exists for the current version of scala then include it as a compiler plugin, and ensure that all the sources are downloaded for all the coursier dependencies.

Alternatively, it would be good for users to opt in using some custom code that could be copy/pasted into their user configuration.

Ideally, the decision to use ensime would be based on the user rather than the file, since the lack of the ensime jar would make the files non-portable. However, as a last resort, having the ability to support local jar files that can reference the version of scala used by the project would be a suitable workaround.

Describe alternatives you’ve considered

https://scala-cli.virtuslab.org/docs/reference/directives/#compiler-plugins requires compiler plugins to be published ivy or maven style, which would require users to locally publish a custom assembly jar, which would be a lot of work for them.

Additional context

One of the features of the ensime compiler is to hijack the global.reporter during the compile. I would like to understand how scala-cli sets and uses the Reporter to understand if this would cause a problem. Every invocation compile in sbt will result in a fresh Reporter being used, which is ideal, but if the same reporter is reused then it might cause problems for this feature.

References

Example plugins for sbt and mill can be found in the .tar.gz at https://ensime.github.io/ copied here for convenience

package ensime

import sbt._
import Keys._

object EnsimePlugin extends AutoPlugin {
  override def trigger = allRequirements

  object autoImport {
    val ensimeJar = taskKey[File]("Location of ENSIME")
  }

  import autoImport._
  override lazy val globalSettings: Seq[Setting[_]] = Seq(
    // perhaps an overreach...
    transitiveClassifiers := Seq("sources")
  )

  override lazy val projectSettings: Seq[Setting[_]] = Seq(
    ensimeJar := (Def.taskDyn {
      val jar = file(s"""${sys.props("user.home")}/.cache/ensime/lib/ensime-${scalaVersion.value}.jar""")
      if (jar.isFile) Def.task {
        // make sure the user always has sources if ENSIME is enabled
        val _ = updateClassifiers.value
        jar
      } else Def.task {
        streams.value.log.warn(s"ENSIME not found. Try\n\n      sbt ++${scalaVersion.value}! install\n\nin the ensime-tng repo.")
        jar
      }
    }).value,

    scalacOptions ++= {
      val jar = ensimeJar.value
      if (jar.isFile) Seq(s"-Xplugin:${jar.getAbsolutePath}")
      else Seq()
    },

    clean := {
      val _ = clean.value
      // clears the reverse lookup of source files to the target
      file(s"""${sys.props("user.home")}/.cache/ensime${target.value}""").delete(): Unit
    }
  )
}
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()
    }
  }
}

Issue Analytics

  • State:open
  • Created a year ago
  • Reactions:1
  • Comments:13 (7 by maintainers)

github_iconTop GitHub Comments

1reaction
tgodzikcommented, Oct 28, 2022

Ok so I think ideal scenario here and what this issue can address is: Add a global configuration option that would do ensimeEnable=true/false. It would add the plugin if it exists at a certain path to the compiler if the versions match and download sources by default. If anyone feels there is a better way let me know.

However, I don’t think we will be working on it any time soon unless there is a significant interest. We would be happy to accept outside contribution if there is anyone that wants to help out.

As the current workaround the users should:

  • add the plugin via //> using options "-Xplugin:/home/user/.cache/ensime/lib/ensime-2.13.17.jar"
  • download sources via coursier or add a classifier "org:::name:version,classifier=sources"
0reactions
tgodzikcommented, Oct 31, 2022

I don’t think we will be working on it any time soon unless there is a significant interest.

what would you consider to be significant interest? N users voting for the issue, or something like that?

I want to setup a feature requests list similar to the one we have in Metals, but I haven’t yet worked on it. So I would say voting on it, yeah.

Read more comments on GitHub >

github_iconTop Results From Across the Web

ENSIME
ENSIME pioneered community-oriented development in the Scala community and was the first to introduce a truly inclusive code of conduct.
Read more >
ENSIME: The Next Generation - Tooling - Scala Contributors
ENSIME :TNG runs as a compiler plugin, extracting compiler settings in a build-tool agnostic manner. The same plugin is invoked through its command...
Read more >
ENSIME - GitHub
ENhanced Scala Interaction Mode for Emacs. ENSIME has one repository available. Follow their code on GitHub.
Read more >
ensime - Wiktionary
FrenchEdit. VerbEdit. ensime. inflection of ensimer: first/third-person singular present indicative/subjunctive · second-person singular imperative.
Read more >
ENSIME: What It Is and Why We Care - ProTech Training
Most people have heard of ENSIME by now as the go-to mode for Scala editing in Emacs. This alone is quite awesome, but...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found