Skip to content

Commit

Permalink
Convert sbt style deps on paste in for scala-cli
Browse files Browse the repository at this point in the history
  • Loading branch information
majk-p authored and tgodzik committed Feb 2, 2025
1 parent b86a6ce commit 8195f99
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import scala.meta.internal.metals.Buffers
import scala.meta.internal.metals.MetalsEnrichments._
import scala.meta.internal.metals.codeactions.CodeAction
import scala.meta.internal.metals.codeactions.MillifyScalaCliDependencyCodeAction._
import scala.meta.internal.metals.scalacli.DependencyConverter
import scala.meta.internal.parsing.Trees
import scala.meta.io.AbsolutePath
import scala.meta.pc.CancelToken
Expand Down Expand Up @@ -47,7 +48,8 @@ class MillifyScalaCliDependencyCodeAction(buffers: Buffers) extends CodeAction {
.collectFirst {
case comment: Comment
if isScalaCliUsingDirectiveComment(comment.toString()) =>
convertSbtToMillStyleIfPossible(comment.toString())
DependencyConverter
.convertSbtToMillStyleIfPossible(comment.toString())
.map(
buildAction(comment, kind, path, range.getStart.getLine)(_)
)
Expand All @@ -67,7 +69,7 @@ object MillifyScalaCliDependencyCodeAction {
path: AbsolutePath,
commentStartLine: Int,
)(
suggestion: ReplacementSuggestion
suggestion: DependencyConverter.ReplacementSuggestion
) = {
val pos = new l.Range(
new l.Position(
Expand All @@ -84,51 +86,15 @@ object MillifyScalaCliDependencyCodeAction {
kind = kind,
changes = List(
path -> List(
new l.TextEdit(pos, suggestion.replacementText)
new l.TextEdit(pos, suggestion.replacementDirective)
)
),
)
}

private def convertSbtToMillStyleIfPossible(
sbtStyleDirective: String
): Option[ReplacementSuggestion] =
sbtStyleDirective.split(" ").filterNot(_.isEmpty) match {
case Array(
"//>",
"using",
dependencyIdentifierLike,
groupId,
groupDelimiter,
artifactId,
"%",
version,
)
if dependencyIdentifiers(dependencyIdentifierLike) &&
sbtDependencyDelimiters(groupDelimiter) =>
val groupArtifactJoin = groupDelimiter.replace('%', ':')
val millStyleDependency =
s"$groupId$groupArtifactJoin$artifactId:$version".replace("\"", "")
Some(
ReplacementSuggestion(dependencyIdentifierLike, millStyleDependency)
)
case _ => None
}

private val dependencyIdentifiers = Set("dep", "lib", "plugin")
private val sbtDependencyDelimiters = Set("%", "%%", "%%%")

private def actionTitle(millStyleDependency: String): String =
s"""Convert to "$millStyleDependency""""

private case class ReplacementSuggestion(
dependencyIdentifier: String,
millStyleDependency: String,
) {
val replacementText: String =
s"//> using $dependencyIdentifier \"$millStyleDependency\""
}

private[codeactions] def isScalaCliUsingDirectiveComment(
text: String
): Boolean =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class RangeFormattingProvider(
userConfig: () => UserConfiguration,
) {
val formatters: List[RangeFormatter] = List(
ScalaCliDependencyRangeFormatter,
MultilineString(userConfig),
IndentOnPaste(userConfig),
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package scala.meta.internal.metals.formatting

import scala.meta.internal.metals.formatting.RangeFormatter
import scala.meta.internal.metals.formatting.RangeFormatterParams
import scala.meta.internal.metals.scalacli.DependencyConverter

import org.eclipse.{lsp4j => l}

object ScalaCliDependencyRangeFormatter extends RangeFormatter {

override def contribute(
range: RangeFormatterParams
): Option[List[l.TextEdit]] = {

val line = range.sourceText.substring(
range.startPos.start - range.startPos.startColumn,
range.endPos.end,
)
DependencyConverter
.convertSbtToMillStyleIfPossible(
line
)
.map(converted =>
new l.TextEdit(range.range, converted.millStyleDependency)
)
.map(List(_))

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package scala.meta.internal.metals.scalacli

object DependencyConverter {
def convertSbtToMillStyleIfPossible(
sbtStyleDirective: String
): Option[ReplacementSuggestion] =
sbtStyleDirective.split(" ").filterNot(_.isEmpty) match {
case Array(
"//>",
"using",
dependencyIdentifierLike,
groupId,
groupDelimiter,
artifactId,
"%",
version,
)
if dependencyIdentifiers(dependencyIdentifierLike) &&
sbtDependencyDelimiters(groupDelimiter) =>
val groupArtifactJoin = groupDelimiter.replace('%', ':')
val millStyleDependency =
s"$groupId$groupArtifactJoin$artifactId:$version".replace("\"", "")
Some(
ReplacementSuggestion(dependencyIdentifierLike, millStyleDependency)
)
case _ => None
}

private val dependencyIdentifiers = Set("dep", "lib", "plugin")
private val sbtDependencyDelimiters = Set("%", "%%", "%%%")

case class ReplacementSuggestion(
dependencyIdentifier: String,
millStyleDependency: String,
) {
val replacementDirective: String =
s"//> using $dependencyIdentifier \"$millStyleDependency\""
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package tests.rangeFormatting

import munit.Location
import munit.TestOptions
import org.eclipse.lsp4j.FormattingOptions
import tests.BaseLspSuite

class ScalaCliDependencyRangeFormatterPastingSuite
extends BaseLspSuite("MillifyRangeFormatting") {

check(
"change-dep-format-on-paste",
s"""
|//> using dep @@
|object Main {
| println("hello")
|}""".stripMargin,
s"""|"org.scalameta" %% "munit" % "0.7.26"""".stripMargin,
s"""
|//> using dep org.scalameta::munit:0.7.26
|object Main {
| println("hello")
|}""".stripMargin,
)

check(
"change-dep-format-within-existing-deps",
s"""
|//> using dep com.lihaoyi::utest::0.7.10
|//> using dep @@
|//> using dep com.lihaoyi::pprint::0.6.6
|object Main {
| println("hello")
|}""".stripMargin,
s"""|"org.scalameta" %% "munit" % "0.7.26"""".stripMargin,
s"""
|//> using dep com.lihaoyi::utest::0.7.10
|//> using dep org.scalameta::munit:0.7.26
|//> using dep com.lihaoyi::pprint::0.6.6
|object Main {
| println("hello")
|}""".stripMargin,
)

check(
"not-change-format-outside-using-directive",
s"""
|//> using dep com.lihaoyi::utest::0.7.10
|//> using dep com.lihaoyi::pprint::0.6.6
|// TODO: @@
|object Main {
| println("hello")
|}""".stripMargin,
s"""|"org.scalameta" %% "munit" % "0.7.26"""".stripMargin,
s"""
|//> using dep com.lihaoyi::utest::0.7.10
|//> using dep com.lihaoyi::pprint::0.6.6
|// TODO: "org.scalameta" %% "munit" % "0.7.26"
|object Main {
| println("hello")
|}""".stripMargin,
)

val formattingOptions = new FormattingOptions(2, true)

// TODO this function should be deduplicated across suites
def check(
name: TestOptions,
testCase: String,
paste: String,
expectedCase: String,
)(implicit loc: Location): Unit = {
val tripleQuote = "\"\"\""
def unmangle(string: String): String =
string.replaceAll("'''", tripleQuote)

val testCode = unmangle(testCase)
val base = testCode.replaceAll("(@@)", "")
val expected = unmangle(expectedCase)
test(name) {
for {
_ <- initialize(
s"""/metals.json
|{"a":{}}
|/a/src/main/scala/a/Main.scala
|""".stripMargin + base
)
_ <- server.didOpen("a/src/main/scala/a/Main.scala")
_ <- server.rangeFormatting(
"a/src/main/scala/a/Main.scala",
testCode, // bez @@
expected,
unmangle(paste),
workspace,
Some(formattingOptions),
)
} yield ()
}
}
}

0 comments on commit 8195f99

Please sign in to comment.