Skip to content

Commit

Permalink
improvement: Use inlay hints for worksheets
Browse files Browse the repository at this point in the history
Advantages:
- this would allow us to stop using a custom extension and support more editors such as Zed
- can reuse any new feature inlay hints add
- reevaluate on change? (or should we remove it?)

Disadvantages:
- no way to set color
- could mix with normal decorations

TODO:

- [ ] gather feedback
- [ ] fix tests
- [ ] check if we can remove other ways of publishing altogether
  • Loading branch information
tgodzik committed Oct 7, 2024
1 parent 48dcf96 commit 5e92f76
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,19 @@ final class InlayHintResolveProvider(
token: CancelToken,
): Future[InlayHint] = {
scala.util.Try {
val data = inlayHint.getData().asInstanceOf[JsonArray]
getLabelParts(inlayHint).zip(parseData(data))
Option(inlayHint.getData()) match {
case Some(data: JsonArray) =>
resolve(
inlayHint,
getLabelParts(inlayHint).zip(parseData(data)),
path,
token,
)

case _ => Future.successful(inlayHint)
}
}.toEither match {
case Right(labelParts) =>
resolve(inlayHint, labelParts, path, token)
case Right(labelParts) => labelParts
case Left(error) =>
scribe.warn(s"Failed to resolve inlay hint: $error")
rc.unsanitized.create(report(inlayHint, path, error), ifVerbose = true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ abstract class MetalsLspService(
compilations,
scalaVersionSelector,
clientConfig.initialConfig,
clientConfig.isInlayHintsEnabled(),
)
)
}
Expand Down Expand Up @@ -1014,7 +1015,11 @@ abstract class MetalsLspService(
if (userConfig.areSyntheticsEnabled())
compilers.inlayHints(params, token)
else Future.successful(List.empty[l.InlayHint].asJava)
} yield hints
worksheet <- worksheetProvider.inlayHints(
params.getTextDocument().getUri().toAbsolutePath,
token,
)
} yield (hints.asScala ++ worksheet).asJava
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import scala.meta.internal.metals.Compilations
import scala.meta.internal.metals.Diagnostics
import scala.meta.internal.metals.Embedded
import scala.meta.internal.metals.Messages
import scala.meta.internal.metals.MetalsEnrichments._
import scala.meta.internal.metals.MetalsServerConfig
import scala.meta.internal.metals.MutableCancelable
import scala.meta.internal.metals.ScalaVersionSelector
Expand All @@ -54,6 +53,9 @@ import mdoc.interfaces.Mdoc
import org.eclipse.lsp4j.Hover
import org.eclipse.lsp4j.MessageType
import org.eclipse.lsp4j.Position
import org.eclipse.lsp4j.InlayHint
import org.eclipse.lsp4j.jsonrpc.messages
import scala.meta.internal.metals.MetalsEnrichments._

/**
* Implements interactive worksheets for "*.worksheet.sc" file extensions.
Expand All @@ -73,6 +75,7 @@ class WorksheetProvider(
compilations: Compilations,
scalaVersionSelector: ScalaVersionSelector,
serverConfig: MetalsServerConfig,
isInlayHintsProvider: Boolean,
)(implicit ec: ExecutionContext)
extends Cancelable {

Expand Down Expand Up @@ -135,7 +138,7 @@ class WorksheetProvider(
}

def onDidFocus(path: AbsolutePath): Future[Unit] = Future {
if (path.isWorksheet) {
if (!isInlayHintsProvider) {
val input = path.toInputFromBuffers(buffers)
exportableEvaluations.get(input) match {
case Some(evaluatedWorksheet) =>
Expand All @@ -145,10 +148,11 @@ class WorksheetProvider(
}
}

def evaluateAndPublish(
private def evaluateAndPublish[T](
path: AbsolutePath,
token: CancelToken,
): Future[Unit] = {
publish: Option[EvaluatedWorksheet] => T,
): Future[T] = {
val possibleBuildTarget = buildTargets.inverseSources(path)
val previouslyCompiled = compilations.previouslyCompiled.toSeq

Expand All @@ -160,11 +164,51 @@ class WorksheetProvider(
compilations.compileTarget(bdi).ignoreValue
case _ =>
Future.successful(())
}).flatMap(_ =>
evaluateAsync(path, token).map(
_.foreach(publisher.publish(languageClient, path, _))
}).flatMap(_ => evaluateAsync(path, token).map(publish))
}

def evaluateAndPublish(
path: AbsolutePath,
token: CancelToken,
): Future[Unit] = {
if (isInlayHintsProvider)
Future.successful(())
else
evaluateAndPublish(
path,
token,
_.foreach(publisher.publish(languageClient, path, _)),
)
}

def inlayHints(
path: AbsolutePath,
token: CancelToken,
) = if (path.isWorksheet) {
evaluateAndPublish(
path,
token,
toInlayHints,
)
} else Future.successful(Nil)

private def toInlayHints(worksheet: Option[EvaluatedWorksheet]) = {
worksheet match {
case None => Nil
case Some(value) =>
value
.statements()
.map { stat =>
val hint = new InlayHint(
stat.position().toLsp.getEnd(),
messages.Either.forLeft(stat.summary()),
)
hint.setTooltip(stat.details())
hint
}
.asScala
.toList
}
}

/**
Expand Down

0 comments on commit 5e92f76

Please sign in to comment.