Skip to content

Commit

Permalink
Merge pull request #65 from kubukoz/build-load-handling
Browse files Browse the repository at this point in the history
  • Loading branch information
kubukoz committed Aug 9, 2022
2 parents 1fa1eeb + 01d1227 commit 835f393
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 39 deletions.
5 changes: 5 additions & 0 deletions lsp/src/main/scala/playground/lsp/BuildLoader.scala
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ object BuildLoader {

case class Loaded(config: BuildConfig, configFilePath: Path)

object Loaded {
// Path is irrelevant when no imports are provided.
val default: Loaded = Loaded(BuildConfig(), Path("/"))
}

def instance[F[_]: TextDocumentProvider: Sync]: BuildLoader[F] =
new BuildLoader[F] {

Expand Down
75 changes: 47 additions & 28 deletions lsp/src/main/scala/playground/lsp/LanguageServer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import smithy4s.dynamic.DynamicSchemaIndex

import scala.jdk.CollectionConverters._
import scala.util.chaining._
import playground.lsp.buildinfo.BuildInfo

trait LanguageServer[F[_]] {
def initialize(params: InitializeParams): F[InitializeResult]
Expand Down Expand Up @@ -90,7 +91,21 @@ object LanguageServer {
.tap(_.setDiagnosticProvider(new DiagnosticRegistrationOptions()))
.tap(_.setCodeLensProvider(new CodeLensOptions()))

new InitializeResult(capabilities).pure[F]
LanguageClient[F]
.showInfoMessage(s"Hello from Smithy Playground v${BuildInfo.version}") *>
ServerLoader[F]
.prepare
.flatMap { prepped =>
ServerLoader[F].perform(prepped.params).flatTap { stats =>
LanguageClient[F]
.showInfoMessage(
s"Loaded Smithy Playground server with ${stats.render}"
)
}
}
.onError { case e => LanguageClient[F].showErrorMessage(e.getMessage()) }
.attempt
.as(new InitializeResult(capabilities))
}

def initialized(params: InitializedParams): F[Unit] = Applicative[F].unit
Expand Down Expand Up @@ -200,34 +215,38 @@ object LanguageServer {

def didChangeWatchedFiles(
params: DidChangeWatchedFilesParams
): F[Unit] = ServerLoader[F].prepare.flatMap {
case prepared if !prepared.isChanged =>
LanguageClient[F].showInfoMessage(
"No change detected, not rebuilding server"
): F[Unit] = ServerLoader[F]
.prepare
.flatMap {
case prepared if !prepared.isChanged =>
LanguageClient[F].showInfoMessage(
"No change detected, not rebuilding server"
)
case prepared =>
LanguageClient[F].showInfoMessage("Detected changes, will try to rebuild server...") *>
ServerLoader[F]
.perform(prepared.params)
.onError { case e =>
LanguageClient[F].showErrorMessage(
"Couldn't reload server: " + e.getMessage
)
}
.flatMap { stats =>
// Can't make (and wait for) client requests while handling a client request (file change)
{
LanguageClient[F].refreshDiagnostics *>
LanguageClient[F].refreshCodeLenses *> LanguageClient[F]
.showInfoMessage(
s"Reloaded Smithy Playground server with ${stats.render}"
)
}.supervise(sup).void
}
}
.onError { case e =>
LanguageClient[F].showErrorMessage(
s"Couldn't rebuild server. Check your config file and the output panel.\nError: ${e.getMessage()}"
)
case prepared =>
LanguageClient[F].showInfoMessage("Detected changes, will try to rebuild server...") *>
ServerLoader[F]
.perform(prepared.params)
.onError { case e =>
LanguageClient[F].showErrorMessage(
"Couldn't reload server: " + e.getMessage
)
}
.flatMap { stats =>
// Can't make (and wait for) client requests while handling a client request (file change)
{
LanguageClient[F].refreshDiagnostics *>
LanguageClient[F].refreshCodeLenses *> LanguageClient[F]
.showInfoMessage(
s"Reloaded Smithy Playground server with " +
s"${stats.importCount} imports, " +
s"${stats.dependencyCount} dependencies and " +
s"${stats.pluginCount} plugins"
)
}.supervise(sup).void
}
}
}

def executeCommand(
params: ExecuteCommandParams
Expand Down
3 changes: 0 additions & 3 deletions lsp/src/main/scala/playground/lsp/Main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import cats.effect.std.Dispatcher
import cats.implicits._
import org.eclipse.lsp4j.launch.LSPLauncher
import playground.TextDocumentManager
import playground.lsp.buildinfo.BuildInfo

import java.io.File
import java.io.FileOutputStream
Expand Down Expand Up @@ -80,8 +79,6 @@ object Main extends IOApp.Simple {

log[IO]("connecting") *>
clientRef.complete(LanguageClient.adapt[IO](launcher.getRemoteProxy())) *>
LanguageClient[IO]
.showInfoMessage(s"Hello from Smithy Playground v${BuildInfo.version}") *>
log[IO]("Server connected")
.as(launcher)
}
Expand Down
28 changes: 20 additions & 8 deletions lsp/src/main/scala/playground/lsp/ServerLoader.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,16 @@ trait ServerLoader[F[_]] {
object ServerLoader {
def apply[F[_]](implicit F: ServerLoader[F]): F.type = F

type Aux[F[_], Params_] = ServerLoader[F] { type Params = Params_ }

case class PrepareResult[A](params: A, isChanged: Boolean)
case class WorkspaceStats(importCount: Int, dependencyCount: Int, pluginCount: Int)

case class WorkspaceStats(importCount: Int, dependencyCount: Int, pluginCount: Int) {

def render: String =
s"$importCount imports, $dependencyCount dependencies and $pluginCount plugins"

}

object WorkspaceStats {

Expand All @@ -28,14 +36,17 @@ object ServerLoader {

}

def instance[F[_]: ServerBuilder: BuildLoader: Ref.Make: MonadThrow]: F[ServerLoader[F]] = {
def instance[
F[_]: ServerBuilder: BuildLoader: Ref.Make: MonadThrow
]: F[ServerLoader.Aux[F, BuildLoader.Loaded]] = {
case class State(currentServer: LanguageServer[F], lastUsedConfig: Option[BuildConfig])
object State {
val initial: State = apply(LanguageServer.notAvailable[F], none)
}

Ref[F].of(State.initial).flatMap { serverRef =>
val instance =
Ref[F]
.of(State.initial)
.map[ServerLoader.Aux[F, BuildLoader.Loaded]] { serverRef =>
new ServerLoader[F] {
type Params = BuildLoader.Loaded

Expand All @@ -54,10 +65,11 @@ object ServerLoader {

val server: LanguageServer[F] = LanguageServer.defer(serverRef.get.map(_.currentServer))
}

// Initial load
BuildLoader[F].load.flatMap(instance.perform).as(instance)
}
}
.flatTap { serverLoader =>
// loading with dummy config to initialize server without dependencies
serverLoader.perform(BuildLoader.Loaded.default)
}
}

}

0 comments on commit 835f393

Please sign in to comment.