Skip to content

Commit

Permalink
improvement: Dependency version completions for scala native and scal…
Browse files Browse the repository at this point in the history
…a js

Scala CLI and mill support syntax <org>::<name>::<version> for scala native and scala js dependencies.
For Scala CLI we can default to it
  • Loading branch information
jkciesluk committed Jun 29, 2023
1 parent 14b56d9 commit 5df3d68
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,35 +20,62 @@ class CoursierComplete(scalaVersion: String) {
else scalaVersion.split('.').take(2).mkString(".")
)

private def completions(s: String): List[String] = {
val futureCompletions = Future {
api.withInput(s).complete().getCompletions().asScala.toList
}
try Await.result(futureCompletions, 10.seconds)
catch {
case _: Throwable => Nil
}
}

def complete(
dependency: String,
includeScala: Boolean = true
includeScala: Boolean = true,
supportNonJvm: Boolean = true
): List[String] = {
// Version completions
if (dependency.replaceAll(":+", ":").count(_ == ':') == 2) {
versionCompletions(dependency, supportNonJvm)
} else {
val javaCompletions = completions(dependency)
val scalaCompletions =
if (
includeScala &&
dependency.endsWith(":") && dependency.count(_ == ':') == 1
)
completions(dependency + ":").map(":" + _)
else List.empty

def completions(s: String): List[String] = {
val futureCompletions = Future {
api.withInput(s).complete().getCompletions().asScala.toList
}
try Await.result(futureCompletions, 10.seconds)
catch {
case _: Throwable => Nil
}
(scalaCompletions ++ javaCompletions).distinct
}
}

private def versionCompletions(
dependency: String,
supportNonJvm: Boolean
): List[String] = {
val (adjusted, hasDoubleColon) = adjustDoubleColon(dependency)
val sortedCompletions = completions(adjusted).sortWith(
Version.fromString(_) >= Version.fromString(_)
)
if (!hasDoubleColon && supportNonJvm)
sortedCompletions.map(":" + _)
else sortedCompletions

}

private def adjustDoubleColon(dependency: String): (String, Boolean) = {
val doubleColon = dependency.lastIndexOf("::")
val firstColon = dependency.indexOf(":")

if (doubleColon > firstColon) {
val depString = (dependency.substring(0, doubleColon) +
dependency.substring(doubleColon + 1, dependency.length()))
(depString, true)
} else (dependency, false)

val javaCompletions = completions(dependency)
val scalaCompletions =
if (
includeScala &&
dependency.endsWith(":") && dependency.count(_ == ':') == 1
)
completions(dependency + ":").map(":" + _)
else List.empty

val allCompletions = (scalaCompletions ++ javaCompletions).distinct
// Attempt to sort versions in reverse order
if (dependency.replaceAll(":+", ":").count(_ == ':') == 2)
allCompletions.sortWith(Version.fromString(_) >= Version.fromString(_))
else allCompletions
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@ object SemVer {
def fromString(version: String): Version = {
val parts = version.split("\\.|-")
val Array(major, minor, patch) =
parts.take(3).map(part => Try { part.toInt }.getOrElse(0))
parts.take(3).map(tryToInt)
val (rc, milestone) = parts
.lift(3)
.map { v =>
if (v.startsWith("RC")) (Some(v.stripPrefix("RC").toInt), None)
else if (v.startsWith("M")) (None, Some(v.stripPrefix("M").toInt))
if (v.startsWith("RC")) (Some(tryToInt(v.stripPrefix("RC"))), None)
else if (v.startsWith("M")) (None, Some(tryToInt(v.stripPrefix("M"))))
else (None, None)
}
.getOrElse((None, None))
Expand All @@ -68,6 +68,8 @@ object SemVer {

}

private def tryToInt(s: String): Int = Try { s.toInt }.toOption.getOrElse(0)

def isCompatibleVersion(minimumVersion: String, version: String): Boolean = {
Version.fromString(version) >= Version.fromString(minimumVersion)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,10 @@ trait MillIvyCompletions {
) extends DependencyCompletion {
override def contribute: List[Member] = {
val completions =
coursierComplete.complete(dependency.replace(CURSOR, ""))
coursierComplete.complete(
dependency.replace(CURSOR, ""),
supportNonJvm = false
)
val (editStart, editEnd) =
CoursierComplete.inferEditRange(pos.point, text)
val editRange = pos.withStart(editStart).withEnd(editEnd).toLsp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ trait SbtLibCompletions {
val completions =
coursierComplete.complete(
dependency.replace(CURSOR, ""),
includeScala = false
includeScala = false,
supportNonJvm = false
)
val editRange =
pos.withStart(pos.start + 1).withEnd(pos.end - 1 - cursorLen).toLsp
Expand Down
57 changes: 57 additions & 0 deletions tests/cross/src/test/scala/tests/pc/CompletionMillIvySuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,16 @@ class CompletionMillIvySuite extends BaseCompletionSuite {
filename = "build.sc",
)

checkEdit(
"scala-completions-edit",
"""|val dependency = ivy"io.circe:@@"
|""".stripMargin,
"""|val dependency = ivy"io.circe::circe-config"
|""".stripMargin,
filename = "build.sc",
filter = _ == "circe-config",
)

check(
"scala-completions",
"""|val dependency = ivy"io.circe::circe-core@@"
Expand All @@ -48,4 +58,51 @@ class CompletionMillIvySuite extends BaseCompletionSuite {
|""".stripMargin,
filename = "build.sc",
)

check(
"version-double-colon",
"""|val dependency = ivy"org.typelevel:cats-core_2.11::@@"
|""".stripMargin,
"""|1.0.1
|1.0.0
|1.0.0-RC2
|1.0.0-RC1
|1.0.0-MF
|""".stripMargin,
filter = _.startsWith("1.0"),
filename = "build.sc",
)

checkEdit(
"version-no-double-colon-edit",
"""|val dependency = ivy"org.typelevel:cats-core_2.11:@@"
|""".stripMargin,
"""|val dependency = ivy"org.typelevel:cats-core_2.11:1.0.1"
|""".stripMargin,
filter = _ == "1.0.1",
filename = "build.sc",
)

check(
"version-double-colon2",
"""|val dependency = ivy"org.typelevel:cats-core_2.11::1.0.@@"
|""".stripMargin,
"""|1.0.1
|1.0.0
|1.0.0-RC2
|1.0.0-RC1
|1.0.0-MF
|""".stripMargin,
filename = "build.sc",
)

checkEdit(
"version-double-colon-edit",
"""|val dependency = ivy"org.typelevel:cats-core_2.11::1.0.1@@"
|""".stripMargin,
"""|val dependency = ivy"org.typelevel:cats-core_2.11::1.0.1"
|""".stripMargin,
filename = "build.sc",
)

}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@ class CompletionScalaCliSuite extends BaseCompletionSuite {
"0.14.1",
)

checkEdit(
"version-edit",
"""|//> using lib "io.circe::circe-core_sjs1:0.14.1@@"
|package A
|""".stripMargin,
"""|//> using lib "io.circe::circe-core_sjs1::0.14.1"
|package A
|""".stripMargin,
)

check(
"multiple-libs",
"""|//> using lib "io.circe::circe-core:0.14.0", "io.circe::circe-core_na@@"
Expand Down Expand Up @@ -110,7 +120,7 @@ class CompletionScalaCliSuite extends BaseCompletionSuite {
"""|//> using lib "co.fs2::fs2-core:@@"
|package A
|""".stripMargin,
"""|//> using lib "co.fs2::fs2-core:3.4.0"
"""|//> using lib "co.fs2::fs2-core::3.4.0"
|package A
|""".stripMargin,
filter = _.startsWith("3.4"),
Expand Down Expand Up @@ -144,6 +154,49 @@ class CompletionScalaCliSuite extends BaseCompletionSuite {
|""".stripMargin,
)

check(
"version-double-colon",
"""|//> using lib "com.outr::scribe-cats::@@"
|package A
|""".stripMargin,
"""|3.7.1
|3.7.0
|""".stripMargin,
filter = _.startsWith("3.7"),
)

checkEdit(
"version-double-colon-edit",
"""|//> using lib "com.outr::scribe-cats::@@"
|package A
|""".stripMargin,
"""|//> using lib "com.outr::scribe-cats::3.7.1"
|package A
|""".stripMargin,
filter = _.startsWith("3.7.1"),
)

check(
"version-double-colon2",
"""|//> using lib "com.outr::scribe-cats::3.7@@"
|package A
|""".stripMargin,
"""|3.7.1
|3.7.0
|""".stripMargin,
)

checkEdit(
"version-double-colon-edit2",
"""|//> using lib "com.outr::scribe-cats::3.7@@"
|package A
|""".stripMargin,
"""|//> using lib "com.outr::scribe-cats::3.7.1"
|package A
|""".stripMargin,
filter = _.startsWith("3.7.1"),
)

private def scriptWrapper(code: String, filename: String): String =
// Vaguely looks like a scala file that ScalaCLI generates
// from a sc file.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ class ScalaCliActionsSuite
val newestOsLib: String = coursierComplete
.complete("com.lihaoyi::os-lib:")
.headOption
.map(_.stripPrefix(":"))
.getOrElse("0.8.1")

checkScalaCLI(
Expand Down

0 comments on commit 5df3d68

Please sign in to comment.