@@ -35,13 +35,15 @@ import LoggingUtils.*
3535import ScalaBuildTargetInformation .*
3636
3737class ServerImpl (
38- stateManager : StateManager ,
3938 pcProvider : PresentationCompilerProvider ,
4039 cancelTokens : IOCancelTokens ,
4140 diagnosticManager : DiagnosticManager ,
4241 steward : ResourceSupervisor [IO ],
4342 bspClientDeferred : Deferred [IO , BuildServer ],
44- lspClient : SlsLanguageClient [IO ]
43+ lspClient : SlsLanguageClient [IO ],
44+ computationQueue : ComputationQueue ,
45+ textDocumentSyncManager : TextDocumentSyncManager ,
46+ bspStateManager : BspStateManager ,
4547) extends SlsLanguageServer [IO ] {
4648
4749 /* There can only be one client for one language-server */
@@ -76,57 +78,61 @@ class ServerImpl(
7678 )).guaranteeCase(s => lspClient.logMessage(s " closing initalize with $s" ))
7779 }
7880
79- def initialized (params : lsp.InitializedParams ): IO [Unit ] = stateManager.importBuild
80- def textDocumentCompletionOp (params : lsp.CompletionParams ): IO [lsp.TextDocumentCompletionOpOutput ] = handleCompletion(
81- params
82- )
83- def textDocumentDefinitionOp (params : lsp.DefinitionParams ): IO [lsp.TextDocumentDefinitionOpOutput ] = handleDefinition(
84- params
85- )
81+ def initialized (params : lsp.InitializedParams ): IO [Unit ] = computationQueue.synchronously {
82+ bspStateManager.importBuild
83+ }
84+
85+ def textDocumentCompletionOp (params : lsp.CompletionParams ): IO [lsp.TextDocumentCompletionOpOutput ] = handleCompletion(params)
86+ def textDocumentDefinitionOp (params : lsp.DefinitionParams ): IO [lsp.TextDocumentDefinitionOpOutput ] = handleDefinition(params)
8687 def textDocumentDidChange (params : lsp.DidChangeTextDocumentParams ): IO [Unit ] = handleDidChange(params)
8788 def textDocumentDidClose (params : lsp.DidCloseTextDocumentParams ): IO [Unit ] = handleDidClose(params)
8889 def textDocumentDidOpen (params : lsp.DidOpenTextDocumentParams ): IO [Unit ] = handleDidOpen(params)
8990 def textDocumentDidSave (params : lsp.DidSaveTextDocumentParams ): IO [Unit ] = handleDidSave(params)
9091 def textDocumentHoverOp (params : lsp.HoverParams ): IO [lsp.TextDocumentHoverOpOutput ] = handleHover(params)
91- def textDocumentInlayHintOp (params : lsp.InlayHintParams ): IO [lsp.TextDocumentInlayHintOpOutput ] = handleInlayHints(
92- params
93- )
94- def textDocumentSignatureHelpOp (params : lsp.SignatureHelpParams ): IO [lsp.TextDocumentSignatureHelpOpOutput ] =
95- handleSignatureHelp(params)
92+ def textDocumentInlayHintOp (params : lsp.InlayHintParams ): IO [lsp.TextDocumentInlayHintOpOutput ] = handleInlayHints(params)
93+ def textDocumentSignatureHelpOp (params : lsp.SignatureHelpParams ): IO [lsp.TextDocumentSignatureHelpOpOutput ] = handleSignatureHelp(params)
9694
9795 // // TODO: goto type definition with container types
9896 def handleCompletion (params : lsp.CompletionParams ) =
99- offsetParamsRequest(params)(_.complete).map { result =>
100- lsp.TextDocumentCompletionOpOutput (
101- convert[lsp4j.CompletionList , lsp.ListCompletionUnion ](result).some
102- )
97+ computationQueue.synchronously {
98+ offsetParamsRequest(params)(_.complete).map { result =>
99+ lsp.TextDocumentCompletionOpOutput (
100+ convert[lsp4j.CompletionList , lsp.ListCompletionUnion ](result).some
101+ )
102+ }
103103 }
104104
105105 def handleHover (params : lsp.HoverParams ) =
106- offsetParamsRequest(params)(_.hover).map { result =>
107- lsp.TextDocumentHoverOpOutput (
108- result.toScala.map(hoverSig => convert[lsp4j.Hover , lsp.Hover ](hoverSig.toLsp()))
109- )
106+ computationQueue.synchronously {
107+ offsetParamsRequest(params)(_.hover).map { result =>
108+ lsp.TextDocumentHoverOpOutput (
109+ result.toScala.map(hoverSig => convert[lsp4j.Hover , lsp.Hover ](hoverSig.toLsp()))
110+ )
111+ }
110112 }
111113
112114 def handleSignatureHelp (params : lsp.SignatureHelpParams ) =
113- offsetParamsRequest(params)(_.signatureHelp).map { result =>
114- lsp.TextDocumentSignatureHelpOpOutput (
115- convert[lsp4j.SignatureHelp , lsp.SignatureHelp ](result).some
116- )
115+ computationQueue.synchronously {
116+ offsetParamsRequest(params)(_.signatureHelp).map { result =>
117+ lsp.TextDocumentSignatureHelpOpOutput (
118+ convert[lsp4j.SignatureHelp , lsp.SignatureHelp ](result).some
119+ )
120+ }
117121 }
118122
119123 def handleDefinition (params : lsp.DefinitionParams ) =
120- offsetParamsRequest(params)(_.definition).map { result =>
121- lsp.TextDocumentDefinitionOpOutput (
122- result
123- .locations()
124- .asScala
125- .headOption
126- .map(definition =>
127- convert[lsp4j.Location , lsp.DefinitionOrListOfDefinitionLink ](definition)
128- ) // FIXME: missing completion on lsp.TextDocumentDefinitionOpOutput
129- )
124+ computationQueue.synchronously {
125+ offsetParamsRequest(params)(_.definition).map { result =>
126+ lsp.TextDocumentDefinitionOpOutput (
127+ result
128+ .locations()
129+ .asScala
130+ .headOption
131+ .map(definition =>
132+ convert[lsp4j.Location , lsp.DefinitionOrListOfDefinitionLink ](definition)
133+ ) // FIXME: missing completion on lsp.TextDocumentDefinitionOpOutput
134+ )
135+ }
130136 }
131137
132138 def virtualFileParams (uri0 : URI , content : String , token0 : CancelToken ): VirtualFileParams = new VirtualFileParams {
@@ -137,12 +143,12 @@ class ServerImpl(
137143
138144 given Schema [List [lsp.InlayHint ]] = Schema .list(lsp.InlayHint .schema)
139145
140- def handleInlayHints (params : lsp.InlayHintParams ) = {
146+ def handleInlayHints (params : lsp.InlayHintParams ) = computationQueue.synchronously {
141147 val uri0 = summon[WithURI [lsp.InlayHintParams ]].uri(params)
142148
143149 cancelTokens.mkCancelToken.use { token0 =>
144150 for {
145- docState <- stateManager.getDocumentState (uri0)
151+ docState <- textDocumentSyncManager.get (uri0)
146152 inalyHintsParams = new InlayHintsParams {
147153 import docState .*
148154 def implicitConversions (): Boolean = true
@@ -166,12 +172,12 @@ class ServerImpl(
166172
167173 private def offsetParamsRequest [Params : PositionWithURI , Result ](params : Params )(
168174 thunk : PresentationCompiler => OffsetParams => CompletableFuture [Result ]
169- ): IO [Result ] = { // TODO Completion on context bound inserts []
175+ )( using SynchronizedState ) : IO [Result ] = { // TODO Completion on context bound inserts []
170176 val uri = summon[WithURI [Params ]].uri(params)
171177 val position = summon[WithPosition [Params ]].position(params)
172178 cancelTokens.mkCancelToken.use { token =>
173179 for {
174- docState <- stateManager.getDocumentState (uri)
180+ docState <- textDocumentSyncManager.get (uri)
175181 offsetParams = toOffsetParams(position, docState, token)
176182 result <- pcParamsRequest(params, offsetParams)(thunk)
177183 } yield result
@@ -180,20 +186,34 @@ class ServerImpl(
180186
181187 private def pcParamsRequest [Params : WithURI , Result , PcParams ](params : Params , pcParams : PcParams )(
182188 thunk : PresentationCompiler => PcParams => CompletableFuture [Result ]
183- ): IO [Result ] = { // TODO Completion on context bound inserts []
189+ )( using SynchronizedState ) : IO [Result ] = { // TODO Completion on context bound inserts []
184190 val uri = summon[WithURI [Params ]].uri(params)
185191 for {
186- info <- stateManager.getBuildTargetInformation (uri)
192+ info <- bspStateManager.get (uri)
187193 pc <- pcProvider.get(info)
188194 result <- IO .fromCompletableFuture(IO (thunk(pc)(pcParams)))
189195 } yield result
190196 }
191197
192- def handleDidSave (params : lsp.DidSaveTextDocumentParams ) = stateManager.didSave(params)
193-
194- def handleDidOpen (params : lsp.DidOpenTextDocumentParams ) = stateManager.didOpen(params)
198+ def handleDidSave (params : lsp.DidSaveTextDocumentParams ) =
199+ computationQueue.synchronously {
200+ for {
201+ _ <- textDocumentSyncManager.didSave(params)
202+ info <- bspStateManager.get(URI (params.textDocument.uri))
203+ } yield info
204+ }.flatMap { info =>
205+ bspStateManager.bspServer.generic.buildTargetCompile(bsp.CompileParams (targets = List (info.buildTarget.id))) // we need to handle the case:
206+ // User saves, compilation starts, we don't want to block it, completion starts, during completion compilation ends new classfiles emmited. We need to know which classfiles are new.
207+ // I hardly believe that we should use straight to jar compilation for that
208+ }.void
209+
210+ def handleDidOpen (params : lsp.DidOpenTextDocumentParams ) = computationQueue.synchronously {
211+ textDocumentSyncManager.didOpen(params) *> bspStateManager.didOpen(lspClient, params)
212+ }
195213
196- def handleDidClose (params : lsp.DidCloseTextDocumentParams ) = stateManager.didClose(params)
214+ def handleDidClose (params : lsp.DidCloseTextDocumentParams ) = computationQueue.synchronously {
215+ textDocumentSyncManager.didClose(params)
216+ }
197217
198218 implicit val positionTransformer : Transformer [lsp4j.Position , lsp.Position ] =
199219 Transformer .define[lsp4j.Position , lsp.Position ].enableBeanGetters.buildTransformer
@@ -213,31 +233,35 @@ class ServerImpl(
213233 * they are triggered by notification and AFAIK, LSP cancellation only works for requests.
214234 */
215235 def pcDiagnostics (info : ScalaBuildTargetInformation , uri : URI ): IO [Unit ] =
216- cancelTokens.mkCancelToken.use { token =>
217- for {
218- _ <- lspClient.logDebug(" Getting PresentationCompiler diagnostics" )
219- textDocument <- stateManager.getDocumentState(uri)
220- pc <- pcProvider.get(info)
221- params = virtualFileParams(uri, textDocument.content, token)
222- diags <- IO .fromCompletableFuture(IO (pc.didChange(params)))
223- lspDiags = diags
224- .into[List [lsp.Diagnostic ]]
225- .withFieldRenamed(_.everyItem.getRange, _.everyItem.range)
226- .withFieldRenamed(_.everyItem.getMessage, _.everyItem.message)
227- .enableOptionDefaultsToNone
228- .transform
229- _ <- diagnosticManager.didChange(lspClient, uri.toString, lspDiags)
230- } yield ()
236+ computationQueue.synchronously {
237+ cancelTokens.mkCancelToken.use { token =>
238+ for {
239+ _ <- lspClient.logDebug(" Getting PresentationCompiler diagnostics" )
240+ textDocument <- textDocumentSyncManager.get(uri)
241+ pc <- pcProvider.get(info)
242+ params = virtualFileParams(uri, textDocument.content, token)
243+ diags <- IO .fromCompletableFuture(IO (pc.didChange(params)))
244+ lspDiags = diags
245+ .into[List [lsp.Diagnostic ]]
246+ .withFieldRenamed(_.everyItem.getRange, _.everyItem.range)
247+ .withFieldRenamed(_.everyItem.getMessage, _.everyItem.message)
248+ .enableOptionDefaultsToNone
249+ .transform
250+ _ <- diagnosticManager.didChange(lspClient, uri.toString, lspDiags)
251+ } yield ()
252+ }
231253 }
232254
233- params =>
255+ params => computationQueue.synchronously {
234256 for {
235- _ <- stateManager .didChange(params)
257+ _ <- textDocumentSyncManager .didChange(params)
236258 _ <- lspClient.logDebug(" Updated DocumentState" )
237259 uri = URI (params.textDocument.uri)
238- info <- stateManager.getBuildTargetInformation(uri)
239- _ <- if isSupported(info) then debounce.debounce(pcDiagnostics(info, uri)) else IO .unit
240- } yield ()
260+ info <- bspStateManager.get(uri)
261+ } yield (uri, info)
262+ }.flatMap { (uri, info) =>
263+ if isSupported(info) then debounce.debounce(pcDiagnostics(info, uri)) else IO .unit
264+ }
241265 }
242266
243267 private def serverCapabilities : lsp.ServerCapabilities =
0 commit comments