[lsp] added server launcher to start a process that uses std in & out

This commit is contained in:
Sven Efftinge 2016-05-27 10:57:59 +02:00
parent b619a2314e
commit 16c9b7c56e
5 changed files with 139 additions and 9 deletions

View file

@ -50,15 +50,14 @@ import io.typefox.lsapi.WorkspaceSymbolParams
import java.util.List
import org.eclipse.emf.common.util.URI
import org.eclipse.xtend.lib.annotations.Accessors
import org.eclipse.xtext.findReferences.IReferenceFinder.IResourceAccess
import org.eclipse.xtext.ide.editor.contentassist.ContentAssistEntry
import org.eclipse.xtext.ide.server.contentassist.ContentAssistService
import org.eclipse.xtext.ide.server.findReferences.WorkspaceResourceAccess
import org.eclipse.xtext.ide.server.symbol.DocumentSymbolService
import org.eclipse.xtext.resource.IResourceServiceProvider
import org.eclipse.xtext.validation.Issue
import static io.typefox.lsapi.util.LsapiFactories.*
import org.eclipse.xtext.ide.server.findReferences.WorkspaceResourceAccess
/**
*
@ -69,16 +68,18 @@ import org.eclipse.xtext.ide.server.findReferences.WorkspaceResourceAccess
InitializeParams params
@Inject Provider<WorkspaceManager> workspaceManagerProvider
WorkspaceManager workspaceManager
IResourceAccess resourceAccess
@Inject extension UriExtensions
@Inject extension IResourceServiceProvider.Registry languagesRegistry
override InitializeResult initialize(InitializeParams params) {
this.params = params
workspaceManager = workspaceManagerProvider.get
if (params.rootPath === null) {
throw new IllegalArgumentException("Bad initialization request. rootPath must not be null.")
}
val rootURI = URI.createFileURI(params.rootPath)
workspaceManager.initialize(rootURI)[this.publishDiagnostics($0, $1)]
resourceAccess = new WorkspaceResourceAccess(workspaceManager)
workspaceManager.initialize(rootURI)[this.publishDiagnostics($0, $1)]
return new InitializeResultImpl => [
capabilities = new ServerCapabilitiesImpl => [
definitionProvider = true
@ -160,6 +161,8 @@ import org.eclipse.xtext.ide.server.findReferences.WorkspaceResourceAccess
// end file/content change events
// validation stuff
private List<NotificationCallback<PublishDiagnosticsParams>> diagnosticListeners = newArrayList()
WorkspaceResourceAccess resourceAccess
override onPublishDiagnostics(NotificationCallback<PublishDiagnosticsParams> callback) {
diagnosticListeners.add(callback)
@ -218,7 +221,6 @@ import org.eclipse.xtext.ide.server.findReferences.WorkspaceResourceAccess
// end completion stuff
// symbols
override definition(TextDocumentPositionParams params) {
val uri = params.textDocument.uri.toUri
val resourceServiceProvider = uri.resourceServiceProvider
@ -241,13 +243,12 @@ import org.eclipse.xtext.ide.server.findReferences.WorkspaceResourceAccess
return workspaceManager.doRead(uri) [ document, resource |
val offset = document.getOffSet(params.position)
val definitions = if (params.context.includeDeclaration)
documentSymbolService.getDefinitions(resource, offset, resourceAccess)
else
emptyList
val indexData = workspaceManager.index
val references = documentSymbolService.getReferences(resource, offset, resourceAccess, indexData)
val result = definitions + references

View file

@ -0,0 +1,90 @@
/*******************************************************************************
* 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.server
import com.google.inject.Guice
import com.google.inject.Inject
import io.typefox.lsapi.NotificationMessage
import io.typefox.lsapi.json.LanguageServerToJsonAdapter
import io.typefox.lsapi.json.MessageMethods
import java.io.ByteArrayInputStream
import java.io.FileOutputStream
import java.io.PrintStream
import java.util.concurrent.atomic.AtomicBoolean
import org.apache.log4j.Logger
/**
* @author Sven Efftinge - Initial contribution and API
*/
class ServerLauncher {
val LOG = Logger.getLogger(ServerLauncher)
def static void main(String[] args) {
val launcher = Guice.createInjector(new ServerModule).getInstance(ServerLauncher)
launcher.start()
}
@Inject LanguageServerImpl languageServer
private final AtomicBoolean hasExitNotification = new AtomicBoolean(false)
def void start() {
val stdin = System.in
val stdout = System.out
System.setIn(new ByteArrayInputStream(newByteArrayOfSize(0)))
System.setOut(new PrintStream(new FileOutputStream("out.log")))
System.err.println("Starting Xtext Language Server.")
val messageAcceptor = new LanguageServerToJsonAdapter(languageServer) {
override protected _doAccept(NotificationMessage message) {
if (LOG.isDebugEnabled) {
LOG.debug(message)
}
if (message.method == MessageMethods.EXIT) {
hasExitNotification.set(true);
}
super._doAccept(message)
}
override protected sendResponse(String responseId, Object resultValue) {
if (LOG.isDebugEnabled) {
LOG.debug("response : "+resultValue)
}
super.sendResponse(responseId, resultValue)
}
override protected sendNotification(String methodId, Object parameter) {
if (LOG.isDebugEnabled) {
LOG.debug("id"+methodId)
LOG.debug("notification : "+parameter)
}
super.sendNotification(methodId, parameter)
}
override protected sendResponseError(String responseId, String errorMessage, int errorCode, Object errorData) {
if (LOG.isDebugEnabled) {
LOG.debug("id"+responseId)
LOG.debug("error : "+errorMessage)
}
super.sendResponseError(responseId, errorMessage, errorCode, errorData)
}
}
messageAcceptor.connect(stdin, stdout)
messageAcceptor.start
System.err.println("started.")
messageAcceptor.join
while (!hasExitNotification.get) {
Thread.sleep(10_000l)
}
System.err.println("Exit notification received. Good Bye!")
}
}

View file

@ -4,7 +4,7 @@ Bundle-Name: %pluginName
Bundle-SymbolicName: org.eclipse.xtext.ide.tests;singleton:=true
Bundle-Version: 2.10.0.qualifier
Bundle-Localization: plugin
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Bundle-ActivationPolicy: lazy
Bundle-Vendor: %providerName
Require-Bundle: org.eclipse.xtext;visibility:=reexport,

View file

@ -0,0 +1,35 @@
/*******************************************************************************
* 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.server
import io.typefox.lsapi.InitializeParamsImpl
import io.typefox.lsapi.json.JsonBasedLanguageServer
import org.eclipse.xtext.ide.server.ServerLauncher
import org.junit.Test
import java.lang.ProcessBuilder.Redirect
/**
* @author efftinge - Initial contribution and API
*/
class ServerLauncherTest {
@Test def void testServerLaunch() {
val process = new ProcessBuilder("java","-cp",System.getProperty("java.class.path"), "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=1044", ServerLauncher.name).redirectInput(Redirect.PIPE).redirectOutput(Redirect.PIPE).start
try {
val client = new JsonBasedLanguageServer()
client.connect(process.inputStream, process.outputStream)
println(client.initialize(new InitializeParamsImpl() => [
rootPath = "."
]))
} finally {
process.destroy
}
}
}

View file

@ -39,6 +39,10 @@ class ServerTest extends AbstractLanguageServerTest {
'''
initialize
assertEquals("Couldn't resolve reference to TypeDeclaration 'NonExisting'.", diagnostics.values.head.head?.message)
assertEquals(1, diagnostics.values.head.head.range.start.line)
assertEquals(4, diagnostics.values.head.head.range.start.character)
assertEquals(1, diagnostics.values.head.head.range.end.line)
assertEquals(15, diagnostics.values.head.head.range.end.character)
}
@Test