mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-16 00:38:56 +00:00
[lsi] extracted factory methods and json based language server launcher
to lsapi.services project Change-Id: Ifb266b8db0567b25eeafa8d76ba503bea0439fdb Signed-off-by: akosyakov <anton.kosyakov@typefox.io>
This commit is contained in:
parent
c519572159
commit
bb0df97e60
11 changed files with 56 additions and 247 deletions
|
@ -50,7 +50,7 @@ class RequestManager {
|
|||
|
||||
/**
|
||||
* <p>
|
||||
* The given <i>write request</i> will be ran first when <i>all running requests</i> completed.
|
||||
* The given <i>write request</i> will be run first when <i>all running requests</i> completed.
|
||||
* </p>
|
||||
* <p>
|
||||
* Currently <i>running requests</i> will be cancelled.
|
||||
|
@ -85,7 +85,7 @@ class RequestManager {
|
|||
|
||||
/**
|
||||
* <p>
|
||||
* The given <i>read request</i> will be ran:
|
||||
* The given <i>read request</i> will be run:
|
||||
* <ul>
|
||||
* <li>concurrent with <i>running read requests</i>;</li>
|
||||
* <li>first when <i>running write requests</i> completed.</li>
|
||||
|
|
|
@ -11,16 +11,12 @@ import com.google.inject.AbstractModule
|
|||
import com.google.inject.Guice
|
||||
import com.google.inject.Inject
|
||||
import io.typefox.lsapi.Diagnostic
|
||||
import io.typefox.lsapi.DidOpenTextDocumentParamsImpl
|
||||
import io.typefox.lsapi.InitializeParamsImpl
|
||||
import io.typefox.lsapi.InitializeResult
|
||||
import io.typefox.lsapi.Location
|
||||
import io.typefox.lsapi.Position
|
||||
import io.typefox.lsapi.PublishDiagnosticsParams
|
||||
import io.typefox.lsapi.Range
|
||||
import io.typefox.lsapi.TextDocumentIdentifierImpl
|
||||
import io.typefox.lsapi.TextDocumentItemImpl
|
||||
import io.typefox.lsapi.TextDocumentPositionParamsImpl
|
||||
import java.io.File
|
||||
import java.io.FileWriter
|
||||
import java.net.URI
|
||||
|
@ -29,6 +25,7 @@ import java.nio.file.Paths
|
|||
import java.util.List
|
||||
import java.util.Map
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.function.Consumer
|
||||
import org.eclipse.xtext.ide.server.LanguageServerImpl
|
||||
import org.eclipse.xtext.ide.server.ServerModule
|
||||
import org.eclipse.xtext.ide.server.UriExtensions
|
||||
|
@ -39,7 +36,6 @@ import org.eclipse.xtext.util.Modules2
|
|||
import org.junit.Before
|
||||
|
||||
import static io.typefox.lsapi.util.LsapiFactories.*
|
||||
import java.util.function.Consumer
|
||||
|
||||
/**
|
||||
* @author Sven Efftinge - Initial contribution and API
|
||||
|
@ -100,20 +96,17 @@ class AbstractLanguageServerTest implements Consumer<PublishDiagnosticsParams> {
|
|||
}
|
||||
|
||||
protected def InitializeResult initialize((InitializeParamsImpl)=>void initializer) {
|
||||
val params = new InitializeParamsImpl
|
||||
params.rootPath = rootPath.toString
|
||||
val params = newInitializeParams(1, rootPath.toString)
|
||||
initializer?.apply(params)
|
||||
return languageServer.initialize(params).get
|
||||
}
|
||||
|
||||
protected def void open(String fileUri, String model) {
|
||||
languageServer.didOpen(new DidOpenTextDocumentParamsImpl => [
|
||||
textDocument = new TextDocumentItemImpl => [
|
||||
uri = fileUri
|
||||
version = 1
|
||||
text = model
|
||||
]
|
||||
])
|
||||
languageServer.didOpen(newDidOpenTextDocumentParams(fileUri, "testlang", 1, model))
|
||||
}
|
||||
|
||||
protected def void close(String fileUri) {
|
||||
languageServer.didClose(newDidCloseTextDocumentParams(fileUri))
|
||||
}
|
||||
|
||||
def String ->(String path, CharSequence contents) {
|
||||
|
@ -132,21 +125,6 @@ class AbstractLanguageServerTest implements Consumer<PublishDiagnosticsParams> {
|
|||
diagnostics.put(t.uri, t.diagnostics)
|
||||
}
|
||||
|
||||
// FIXME: move to LsapiFactories
|
||||
protected def TextDocumentPositionParamsImpl newPosition(String uri, int line, int column) {
|
||||
val params = new TextDocumentPositionParamsImpl
|
||||
params.textDocument = uri.newIdentifier
|
||||
params.position = newPosition(line, column)
|
||||
return params
|
||||
}
|
||||
|
||||
// FIXME: move to LsapiFactories
|
||||
protected def TextDocumentIdentifierImpl newIdentifier(String uri) {
|
||||
val identifier = new TextDocumentIdentifierImpl
|
||||
identifier.uri = uri
|
||||
return identifier
|
||||
}
|
||||
|
||||
protected def dispatch String toExpectation(List<?> elements) '''
|
||||
«FOR element : elements»
|
||||
«element.toExpectation»
|
||||
|
|
|
@ -11,6 +11,7 @@ import io.typefox.lsapi.CompletionItem
|
|||
import org.eclipse.xtend.lib.annotations.Accessors
|
||||
import org.junit.Test
|
||||
|
||||
import static io.typefox.lsapi.util.LsapiFactories.*
|
||||
import static org.junit.Assert.*
|
||||
|
||||
/**
|
||||
|
@ -67,7 +68,7 @@ class CompletionTest extends AbstractLanguageServerTest {
|
|||
initialize
|
||||
open(fileUri, model)
|
||||
|
||||
val completionItems = languageServer.completion(newPosition(fileUri, line, column))
|
||||
val completionItems = languageServer.completion(newTextDocumentPositionParams(fileUri, line, column))
|
||||
|
||||
val actualCompletionItems = completionItems.get.items.toExpectation
|
||||
assertEquals(expectedCompletionItems, actualCompletionItems)
|
||||
|
|
|
@ -11,6 +11,7 @@ import org.eclipse.xtend.lib.annotations.Accessors
|
|||
import org.junit.Test
|
||||
|
||||
import static org.junit.Assert.*
|
||||
import static io.typefox.lsapi.util.LsapiFactories.*
|
||||
|
||||
/**
|
||||
* @author kosyakov - Initial contribution and API
|
||||
|
@ -43,7 +44,7 @@ class DefinitionTest extends AbstractLanguageServerTest {
|
|||
initialize
|
||||
open(fileUri, model)
|
||||
|
||||
val definitions = languageServer.definition(newPosition(fileUri, line, column))
|
||||
val definitions = languageServer.definition(newTextDocumentPositionParams(fileUri, line, column))
|
||||
val actualDefinitions = definitions.get.toExpectation
|
||||
assertEquals(expectedDefinitions, actualDefinitions)
|
||||
}
|
||||
|
|
|
@ -7,13 +7,14 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.xtext.ide.tests.server
|
||||
|
||||
import io.typefox.lsapi.DocumentSymbolParamsImpl
|
||||
import io.typefox.lsapi.SymbolInformation
|
||||
import org.eclipse.xtend.lib.annotations.Accessors
|
||||
import org.junit.Test
|
||||
|
||||
import static org.junit.Assert.*
|
||||
|
||||
import static extension io.typefox.lsapi.util.LsapiFactories.*
|
||||
|
||||
/**
|
||||
* @author kosyakov - Initial contribution and API
|
||||
*/
|
||||
|
@ -66,9 +67,7 @@ class DocumentSymbolTest extends AbstractLanguageServerTest {
|
|||
initialize
|
||||
open(fileUri, model)
|
||||
|
||||
val symbols = languageServer.documentSymbol(new DocumentSymbolParamsImpl => [
|
||||
textDocument = fileUri.newIdentifier
|
||||
])
|
||||
val symbols = languageServer.documentSymbol(fileUri.newDocumentSymbolParams)
|
||||
val String actualSymbols = symbols.get.toExpectation
|
||||
assertEquals(expectedSymbols, actualSymbols)
|
||||
}
|
||||
|
|
|
@ -7,22 +7,13 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.xtext.ide.tests.server
|
||||
|
||||
import io.typefox.lsapi.DidChangeTextDocumentParamsImpl
|
||||
import io.typefox.lsapi.DidChangeWatchedFilesParamsImpl
|
||||
import io.typefox.lsapi.DidCloseTextDocumentParamsImpl
|
||||
import io.typefox.lsapi.DidOpenTextDocumentParamsImpl
|
||||
import io.typefox.lsapi.FileEvent
|
||||
import io.typefox.lsapi.FileEventImpl
|
||||
import io.typefox.lsapi.PositionImpl
|
||||
import io.typefox.lsapi.RangeImpl
|
||||
import io.typefox.lsapi.TextDocumentContentChangeEventImpl
|
||||
import io.typefox.lsapi.TextDocumentIdentifierImpl
|
||||
import io.typefox.lsapi.TextDocumentItemImpl
|
||||
import io.typefox.lsapi.VersionedTextDocumentIdentifierImpl
|
||||
import org.junit.Test
|
||||
|
||||
import static org.junit.Assert.*
|
||||
|
||||
import static extension io.typefox.lsapi.util.LsapiFactories.*
|
||||
|
||||
/**
|
||||
* @author Sven Efftinge - Initial contribution and API
|
||||
*/
|
||||
|
@ -43,35 +34,24 @@ class OpenDocumentTest extends AbstractLanguageServerTest {
|
|||
type Foo {
|
||||
}
|
||||
'''
|
||||
languageServer.getWorkspaceService.didChangeWatchedFiles(new DidChangeWatchedFilesParamsImpl => [
|
||||
changes = newArrayList(new FileEventImpl => [
|
||||
uri = path
|
||||
type = FileEvent.TYPE_CREATED
|
||||
])
|
||||
])
|
||||
languageServer.getWorkspaceService.didChangeWatchedFiles(
|
||||
#[
|
||||
newFileEvent(path, FileEvent.TYPE_CREATED)
|
||||
].newDidChangeWatchedFilesParams
|
||||
)
|
||||
|
||||
// still errorneous
|
||||
assertEquals("Couldn't resolve reference to TypeDeclaration 'NonExisting'.", diagnostics.get(firstFile).head.message)
|
||||
|
||||
// let's open the document with a different content
|
||||
languageServer.didOpen(new DidOpenTextDocumentParamsImpl => [
|
||||
textDocument = new TextDocumentItemImpl => [
|
||||
uri = path
|
||||
version = 1
|
||||
text = '''
|
||||
type NonExisting {
|
||||
}
|
||||
'''
|
||||
]
|
||||
])
|
||||
open(path, '''
|
||||
type NonExisting {
|
||||
}
|
||||
''')
|
||||
assertNull(diagnostics.get(firstFile).head)
|
||||
|
||||
// let's close again
|
||||
languageServer.didClose(new DidCloseTextDocumentParamsImpl => [
|
||||
textDocument = new TextDocumentIdentifierImpl => [
|
||||
uri = path
|
||||
]
|
||||
])
|
||||
close(path)
|
||||
assertEquals("Couldn't resolve reference to TypeDeclaration 'NonExisting'.", diagnostics.get(firstFile).head.message)
|
||||
}
|
||||
|
||||
|
@ -87,40 +67,16 @@ class OpenDocumentTest extends AbstractLanguageServerTest {
|
|||
|
||||
assertEquals("Couldn't resolve reference to TypeDeclaration 'NonExisting'.", diagnostics.get(firstFile).head.message)
|
||||
|
||||
languageServer.didOpen(new DidOpenTextDocumentParamsImpl => [
|
||||
textDocument = new TextDocumentItemImpl => [
|
||||
uri = firstFile
|
||||
version = 1
|
||||
text = '''
|
||||
type Test {
|
||||
NonExisting foo
|
||||
}
|
||||
'''
|
||||
]
|
||||
])
|
||||
open(firstFile, '''
|
||||
type Test {
|
||||
NonExisting foo
|
||||
}
|
||||
''')
|
||||
assertEquals("Couldn't resolve reference to TypeDeclaration 'NonExisting'.", diagnostics.get(firstFile).head.message)
|
||||
|
||||
languageServer.didChange(new DidChangeTextDocumentParamsImpl => [
|
||||
textDocument = new VersionedTextDocumentIdentifierImpl => [
|
||||
uri = firstFile
|
||||
version = 2
|
||||
]
|
||||
contentChanges = #[
|
||||
new TextDocumentContentChangeEventImpl => [
|
||||
range = new RangeImpl => [
|
||||
start = new PositionImpl => [
|
||||
line = 1
|
||||
character = 4
|
||||
]
|
||||
end = new PositionImpl => [
|
||||
line = 1
|
||||
character = 15
|
||||
]
|
||||
]
|
||||
text = "Test"
|
||||
]
|
||||
]
|
||||
])
|
||||
languageServer.didChange(newDidChangeTextDocumentParamsImpl(firstFile, 2, #[
|
||||
newTextDocumentContentChangeEvent(newRange(newPosition(1, 4), newPosition(1, 15)), null, "Test")
|
||||
]))
|
||||
assertNull(diagnostics.get(firstFile).head)
|
||||
}
|
||||
}
|
|
@ -8,7 +8,6 @@
|
|||
package org.eclipse.xtext.ide.tests.server
|
||||
|
||||
import io.typefox.lsapi.ReferenceContextImpl
|
||||
import io.typefox.lsapi.ReferenceParamsImpl
|
||||
import org.eclipse.xtend.lib.annotations.Accessors
|
||||
import org.junit.Test
|
||||
|
||||
|
@ -53,7 +52,6 @@ class ReferenceTest extends AbstractLanguageServerTest {
|
|||
'''
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
protected def void testReferences((ReferenceTestConfiguration)=>void configurator) {
|
||||
val extension configuration = new ReferenceTestConfiguration
|
||||
|
@ -66,11 +64,7 @@ class ReferenceTest extends AbstractLanguageServerTest {
|
|||
|
||||
val referenceContext = new ReferenceContextImpl
|
||||
referenceContext.includeDeclaration = includeDeclaration
|
||||
val definitions = languageServer.references(new ReferenceParamsImpl => [
|
||||
textDocument = fileUri.newIdentifier
|
||||
position = newPosition(line, column)
|
||||
context = referenceContext
|
||||
])
|
||||
val definitions = languageServer.references(newReferenceParams(fileUri, line, column, referenceContext))
|
||||
val actualDefinitions = definitions.get.toExpectation
|
||||
assertEquals(expectedReferences, actualDefinitions)
|
||||
}
|
||||
|
|
|
@ -7,13 +7,13 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.xtext.ide.tests.server
|
||||
|
||||
import io.typefox.lsapi.DidChangeWatchedFilesParamsImpl
|
||||
import io.typefox.lsapi.FileEvent
|
||||
import io.typefox.lsapi.FileEventImpl
|
||||
import org.junit.Test
|
||||
|
||||
import static org.junit.Assert.*
|
||||
|
||||
import static extension io.typefox.lsapi.util.LsapiFactories.*
|
||||
|
||||
/**
|
||||
* @author Sven Efftinge - Initial contribution and API
|
||||
*/
|
||||
|
@ -59,12 +59,10 @@ class ServerTest extends AbstractLanguageServerTest {
|
|||
type NonExisting {
|
||||
}
|
||||
'''
|
||||
languageServer.getWorkspaceService.didChangeWatchedFiles(new DidChangeWatchedFilesParamsImpl => [
|
||||
changes = newArrayList(new FileEventImpl => [
|
||||
uri = path
|
||||
type = FileEvent.TYPE_CREATED
|
||||
])
|
||||
])
|
||||
|
||||
languageServer.getWorkspaceService.didChangeWatchedFiles(
|
||||
#[newFileEvent(path, FileEvent.TYPE_CREATED)].newDidChangeWatchedFilesParams
|
||||
)
|
||||
assertNotNull(diagnostics.get(path))
|
||||
assertTrue(diagnostics.values.join(','), diagnostics.values.forall[empty])
|
||||
}
|
||||
|
|
|
@ -55,10 +55,9 @@ class RequestManagerTest {
|
|||
}
|
||||
sharedState.incrementAndGet
|
||||
]
|
||||
val future2 = requestManager.runRead [
|
||||
requestManager.runRead [
|
||||
sharedState.incrementAndGet
|
||||
]
|
||||
future2.join
|
||||
future.join
|
||||
assertEquals(2, sharedState.get)
|
||||
}
|
||||
|
@ -87,15 +86,13 @@ class RequestManagerTest {
|
|||
|
||||
@Test
|
||||
def void testRunWriteAfterWrite() {
|
||||
val future = requestManager.runWrite [
|
||||
requestManager.runWrite [
|
||||
sharedState.incrementAndGet
|
||||
]
|
||||
val future2 = requestManager.runWrite [
|
||||
requestManager.runWrite [
|
||||
if (sharedState.get != 0)
|
||||
sharedState.incrementAndGet
|
||||
]
|
||||
future2.join
|
||||
future.join
|
||||
].join
|
||||
assertEquals(2, sharedState.get)
|
||||
}
|
||||
|
||||
|
|
|
@ -8,13 +8,9 @@
|
|||
package org.eclipse.xtext.ide.tests.testlanguage.server
|
||||
|
||||
import com.google.inject.Guice
|
||||
import java.io.IOException
|
||||
import java.io.PrintWriter
|
||||
import io.typefox.lsapi.services.LanguageServer
|
||||
import io.typefox.lsapi.services.json.LanguageServerLauncher
|
||||
import java.net.InetSocketAddress
|
||||
import java.nio.channels.AsynchronousServerSocketChannel
|
||||
import java.nio.channels.AsynchronousSocketChannel
|
||||
import java.nio.channels.Channels
|
||||
import java.nio.channels.CompletionHandler
|
||||
import org.eclipse.xtext.ide.server.ServerModule
|
||||
|
||||
/**
|
||||
|
@ -23,51 +19,13 @@ import org.eclipse.xtext.ide.server.ServerModule
|
|||
class SocketServerLauncher {
|
||||
|
||||
def static void main(String[] args) {
|
||||
var AsynchronousServerSocketChannel serverSocket
|
||||
try {
|
||||
val injector = Guice.createInjector(new ServerModule)
|
||||
val server = injector.getInstance(VSCodeJsonAdapter)
|
||||
server.errorLog = new PrintWriter(System.err)
|
||||
server.messageLog = new PrintWriter(System.out)
|
||||
|
||||
serverSocket = AsynchronousServerSocketChannel.open
|
||||
|
||||
val address = new InetSocketAddress('localhost', 5007)
|
||||
serverSocket.bind(address)
|
||||
println('Listening to ' + address)
|
||||
serverSocket.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() {
|
||||
|
||||
override completed(AsynchronousSocketChannel channel, Object attachment) {
|
||||
val in = Channels.newInputStream(channel)
|
||||
val out = Channels.newOutputStream(channel)
|
||||
println('Connection accepted')
|
||||
|
||||
server.connect(in, out)
|
||||
server.start()
|
||||
server.join()
|
||||
|
||||
channel.close()
|
||||
println('Connection closed')
|
||||
}
|
||||
|
||||
override failed(Throwable exc, Object attachment) {
|
||||
exc.printStackTrace
|
||||
}
|
||||
|
||||
})
|
||||
while (!server.exitRequested) {
|
||||
Thread.sleep(2000)
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace()
|
||||
} finally {
|
||||
if (serverSocket !== null) {
|
||||
try {
|
||||
serverSocket.close()
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
val injector = Guice.createInjector(new ServerModule)
|
||||
val languageServer = injector.getInstance(LanguageServer)
|
||||
val launcher = LanguageServerLauncher.newLoggingLauncher(
|
||||
languageServer,
|
||||
new InetSocketAddress('localhost', 5007)
|
||||
)
|
||||
launcher.launch
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,73 +0,0 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2016 TypeFox GmbH (http://www.typefox.io) and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*******************************************************************************/
|
||||
package org.eclipse.xtext.ide.tests.testlanguage.server
|
||||
|
||||
import com.google.inject.Inject
|
||||
import io.typefox.lsapi.NotificationMessage
|
||||
import io.typefox.lsapi.RequestMessage
|
||||
import io.typefox.lsapi.ResponseMessage
|
||||
import io.typefox.lsapi.services.LanguageServer
|
||||
import io.typefox.lsapi.services.json.LanguageServerToJsonAdapter
|
||||
import io.typefox.lsapi.services.json.MessageMethods
|
||||
import java.io.PrintWriter
|
||||
import org.eclipse.xtend.lib.annotations.Accessors
|
||||
|
||||
class VSCodeJsonAdapter extends LanguageServerToJsonAdapter {
|
||||
|
||||
@Accessors(PUBLIC_SETTER)
|
||||
PrintWriter errorLog
|
||||
|
||||
@Accessors(PUBLIC_SETTER)
|
||||
PrintWriter messageLog
|
||||
|
||||
@Accessors(PUBLIC_GETTER)
|
||||
boolean exitRequested
|
||||
|
||||
@Inject
|
||||
new(LanguageServer server) {
|
||||
super(server)
|
||||
protocol.addErrorListener[ message, throwable |
|
||||
if (errorLog !== null) {
|
||||
if (throwable !== null)
|
||||
throwable.printStackTrace(errorLog)
|
||||
else if (message !== null)
|
||||
errorLog.println(message)
|
||||
errorLog.flush()
|
||||
}
|
||||
]
|
||||
protocol.addIncomingMessageListener[ message, json |
|
||||
if (message instanceof RequestMessage) {
|
||||
switch message.method {
|
||||
case MessageMethods.EXIT:
|
||||
exitRequested = true
|
||||
}
|
||||
}
|
||||
if (messageLog !== null) {
|
||||
switch message {
|
||||
RequestMessage:
|
||||
messageLog.println('Client Request:\n\t' + json)
|
||||
NotificationMessage:
|
||||
messageLog.println('Client Notification:\n\t' + json)
|
||||
}
|
||||
messageLog.flush()
|
||||
}
|
||||
]
|
||||
protocol.addOutgoingMessageListener[ message, json |
|
||||
if (messageLog !== null) {
|
||||
switch message {
|
||||
ResponseMessage:
|
||||
messageLog.println('Server Response:\n\t' + json)
|
||||
NotificationMessage:
|
||||
messageLog.println('Server Notification:\n\t' + json)
|
||||
}
|
||||
messageLog.flush()
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue