From 16c9b7c56ec63a2d817246137cd3671376b92ca7 Mon Sep 17 00:00:00 2001 From: Sven Efftinge Date: Fri, 27 May 2016 10:57:59 +0200 Subject: [PATCH] [lsp] added server launcher to start a process that uses std in & out --- .../xtext/ide/server/LanguageServerImpl.xtend | 17 ++-- .../xtext/ide/server/ServerLauncher.xtend | 90 +++++++++++++++++++ .../META-INF/MANIFEST.MF | 2 +- .../ide/tests/server/ServerLauncherTest.xtend | 35 ++++++++ .../xtext/ide/tests/server/ServerTest.xtend | 4 + 5 files changed, 139 insertions(+), 9 deletions(-) create mode 100644 plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/ServerLauncher.xtend create mode 100644 tests/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/server/ServerLauncherTest.xtend diff --git a/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/LanguageServerImpl.xtend b/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/LanguageServerImpl.xtend index 485ebf940..0ecc30f58 100644 --- a/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/LanguageServerImpl.xtend +++ b/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/LanguageServerImpl.xtend @@ -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 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> diagnosticListeners = newArrayList() + + WorkspaceResourceAccess resourceAccess override onPublishDiagnostics(NotificationCallback 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 diff --git a/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/ServerLauncher.xtend b/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/ServerLauncher.xtend new file mode 100644 index 000000000..11839fbf3 --- /dev/null +++ b/plugins/org.eclipse.xtext.ide/src/org/eclipse/xtext/ide/server/ServerLauncher.xtend @@ -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!") + } + +} \ No newline at end of file diff --git a/tests/org.eclipse.xtext.ide.tests/META-INF/MANIFEST.MF b/tests/org.eclipse.xtext.ide.tests/META-INF/MANIFEST.MF index d1e263222..730e11585 100644 --- a/tests/org.eclipse.xtext.ide.tests/META-INF/MANIFEST.MF +++ b/tests/org.eclipse.xtext.ide.tests/META-INF/MANIFEST.MF @@ -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, diff --git a/tests/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/server/ServerLauncherTest.xtend b/tests/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/server/ServerLauncherTest.xtend new file mode 100644 index 000000000..aad17b16e --- /dev/null +++ b/tests/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/server/ServerLauncherTest.xtend @@ -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 + } + } +} \ No newline at end of file diff --git a/tests/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/server/ServerTest.xtend b/tests/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/server/ServerTest.xtend index 01ea9d93e..086df8cc9 100644 --- a/tests/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/server/ServerTest.xtend +++ b/tests/org.eclipse.xtext.ide.tests/src/org/eclipse/xtext/ide/tests/server/ServerTest.xtend @@ -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