[ide server] added use of LS-API, added simple test for initialization

This commit is contained in:
Sven Efftinge 2016-05-13 14:27:39 +02:00
parent 5c13e51cb5
commit c866c7e061
11 changed files with 372 additions and 4 deletions

View file

@ -9,7 +9,8 @@ Bundle-ActivationPolicy: lazy
Bundle-Vendor: %providerName
Require-Bundle: org.eclipse.xtext;visibility:=reexport,
org.eclipse.xtend.lib,
org.eclipse.core.runtime;bundle-version="3.6.0"
org.eclipse.core.runtime;bundle-version="3.6.0",
io.typefox.lsapi;bundle-version="0.1.0";visibility:=reexport
Import-Package: org.apache.log4j;version="1.2.15"
Export-Package: org.eclipse.xtext.ide;x-friends:="org.eclipse.xtend.ide",
org.eclipse.xtext.ide.editor.bracketmatching;x-friends:="org.eclipse.xtend.ide.common,org.eclipse.xtend.ide",
@ -25,4 +26,5 @@ Export-Package: org.eclipse.xtext.ide;x-friends:="org.eclipse.xtend.ide",
org.eclipse.xtext.ide.editor.navigation,
org.eclipse.xtext.ide.editor.partialEditing,
org.eclipse.xtext.ide.editor.syntaxcoloring,
org.eclipse.xtext.ide.labels;x-friends:="org.eclipse.xtext.web"
org.eclipse.xtext.ide.labels;x-friends:="org.eclipse.xtext.web",
org.eclipse.xtext.ide.server

View file

@ -29,5 +29,10 @@
<artifactId>org.eclipse.xtext</artifactId>
<version>[${project.version}]</version>
</dependency>
<dependency>
<groupId>io.typefox.lsapi</groupId>
<artifactId>lsapi</artifactId>
<version>0.1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,40 @@
/*******************************************************************************
* 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 org.eclipse.xtext.util.IAcceptor
import org.eclipse.emf.common.util.URI
import com.google.inject.ImplementedBy
import java.io.File
/**
* @author efftinge - Initial contribution and API
*/
@ImplementedBy(JavaIoFileSystemScanner)
interface IFileSystemScanner {
def void scan(URI root, IAcceptor<URI> acceptor)
static class JavaIoFileSystemScanner implements IFileSystemScanner {
override scan(URI root, IAcceptor<URI> acceptor) {
val file = new File(root.toFileString)
scanRec(file, acceptor)
}
def void scanRec(File file, IAcceptor<URI> acceptor) {
acceptor.accept(URI.createFileURI(file.absolutePath))
if (file.isDirectory) {
for (f : file.listFiles) {
scanRec(f, acceptor)
}
}
}
}
}

View file

@ -0,0 +1,53 @@
/*******************************************************************************
* 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.Inject
import io.typefox.lsapi.CompletionOptionsImpl
import io.typefox.lsapi.InitializeParams
import io.typefox.lsapi.InitializeResult
import io.typefox.lsapi.InitializeResultImpl
import io.typefox.lsapi.LanguageServer
import io.typefox.lsapi.ServerCapabilitiesImpl
import org.eclipse.xtend.lib.annotations.Accessors
/**
* @author Sven Efftinge - Initial contribution and API
*/
@Accessors class LanguageServerImpl implements LanguageServer {
InitializeParams params
@Inject WorkspaceServiceImpl workspaceService
@Inject TextDocumentServiceImpl textDocumentService
override InitializeResult initialize(InitializeParams params) {
this.params = params
workspaceService.initialize(params, [ textDocumentService.publishDiagnostics($0, $1) ])
return new InitializeResultImpl => [
capabilities = new ServerCapabilitiesImpl => [
completionProvider = new CompletionOptionsImpl => [
resolveProvider = true
triggerCharacters = #["."]
]
]
]
}
override void shutdown() {
}
override textDocumentService() {
textDocumentService
}
override workspaceService() {
workspaceService
}
}

View file

@ -0,0 +1,23 @@
/*******************************************************************************
* 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.AbstractModule
import org.eclipse.xtext.resource.IResourceServiceProvider
import org.eclipse.xtext.resource.impl.ResourceServiceProviderRegistryImpl
/**
* @author Sven Efftinge - Initial contribution and API
*/
class ServerModule extends AbstractModule {
override protected configure() {
bind(IResourceServiceProvider.Registry).toInstance(new ResourceServiceProviderRegistryImpl)
}
}

View file

@ -0,0 +1,71 @@
/*******************************************************************************
* 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 io.typefox.lsapi.Diagnostic
import io.typefox.lsapi.DiagnosticImpl
import io.typefox.lsapi.NotificationCallback
import io.typefox.lsapi.PositionImpl
import io.typefox.lsapi.PublishDiagnosticsParams
import io.typefox.lsapi.RangeImpl
import io.typefox.lsapi.TextDocumentPositionParams
import io.typefox.lsapi.TextDocumentService
import java.util.List
import org.eclipse.xtext.validation.Issue
import org.eclipse.emf.common.util.URI
import io.typefox.lsapi.PublishDiagnosticsParamsImpl
/**
* @author efftinge - Initial contribution and API
*/
class TextDocumentServiceImpl implements TextDocumentService {
override completion(TextDocumentPositionParams position) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
def void publishDiagnostics(URI uri, Iterable<? extends Issue> issues) {
val diagnostics = new PublishDiagnosticsParamsImpl => [
it.uri = uri.toFileString
it.diagnostics = issues.map[toDiagnostic].toList
]
for (diagnosticsCallback : diagnosticListeners) {
diagnosticsCallback.onNotification(diagnostics)
}
}
private def Diagnostic toDiagnostic(Issue issue) {
new DiagnosticImpl => [
code = issue.code
severity = switch issue.severity {
case ERROR : Diagnostic.SEVERITY_ERROR
case WARNING : Diagnostic.SEVERITY_WARNING
case INFO : Diagnostic.SEVERITY_INFO
default : Diagnostic.SEVERITY_HINT
}
message = issue.message
range = new RangeImpl => [
start = new PositionImpl => [
line = issue.lineNumber
character = issue.column
]
end = new PositionImpl => [
line = issue.lineNumber
character = issue.column + issue.length
]
]
]
}
private List<NotificationCallback<PublishDiagnosticsParams>> diagnosticListeners = newArrayList()
override onPublishDiagnostics(NotificationCallback<PublishDiagnosticsParams> callback) {
diagnosticListeners.add(callback)
}
}

View file

@ -0,0 +1,72 @@
/*******************************************************************************
* 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.Inject
import com.google.inject.Provider
import io.typefox.lsapi.DidChangeConfigurationParams
import io.typefox.lsapi.DidChangeWatchedFilesParams
import io.typefox.lsapi.InitializeParams
import io.typefox.lsapi.WorkspaceService
import io.typefox.lsapi.WorkspaceSymbolParams
import org.eclipse.emf.common.util.URI
import org.eclipse.xtext.build.BuildRequest
import org.eclipse.xtext.build.IncrementalBuilder
import org.eclipse.xtext.build.IndexState
import org.eclipse.xtext.resource.IResourceServiceProvider
import org.eclipse.xtext.resource.XtextResourceSet
import org.eclipse.xtext.validation.Issue
/**
* @author efftinge - Initial contribution and API
*/
class WorkspaceServiceImpl implements WorkspaceService {
@Inject
protected IncrementalBuilder incrementalBuilder
@Inject
protected IndexState indexState
@Inject
protected Provider<XtextResourceSet> resourceSetProvider
@Inject
protected IResourceServiceProvider.Registry languagesRegistry
@Inject IFileSystemScanner fileSystemScanner
public def void initialize(InitializeParams params, (URI, Iterable<Issue>)=>void acceptor) {
val uris = newArrayList
fileSystemScanner.scan(URI.createFileURI(params.rootPath)) [uris += it]
incrementalBuilder.build(new BuildRequest => [
it.baseDir = URI.createFileURI(params.rootPath)
it.resourceSet = resourceSetProvider.get
dirtyFiles = uris
afterValidate = [ uri, issues|
if (!issues.empty)
acceptor.apply(uri, issues)
return true
]
],[languagesRegistry.getResourceServiceProvider(it)])
}
override didChangeConfiguraton(DidChangeConfigurationParams param) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override didChangeWatchedFiles(DidChangeWatchedFilesParams param) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override symbol(WorkspaceSymbolParams param) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
}

View file

@ -6,5 +6,5 @@
<classpathentry kind="src" path="xtend-gen"/>
<classpathentry kind="src" path="testlang-src"/>
<classpathentry kind="src" path="testlang-src-gen"/>
<classpathentry kind="output" path="bin"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View file

@ -0,0 +1,3 @@
#org.springsource.ide.eclipse.gradle.core.preferences.GradleProjectPreferences
#Mon Apr 13 08:40:14 CEST 2015
org.springsource.ide.eclipse.gradle.rootprojectloc=../..

View file

@ -10,5 +10,6 @@ Bundle-Vendor: %providerName
Require-Bundle: org.eclipse.xtext;visibility:=reexport,
org.eclipse.xtend.lib,
org.eclipse.core.runtime;bundle-version="3.6.0",
org.eclipse.xtext.ide
org.eclipse.xtext.ide,
org.junit;bundle-version="4.12.0"
Import-Package: org.apache.log4j;version="1.2.15"

View file

@ -0,0 +1,98 @@
/*******************************************************************************
* 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 com.google.inject.Guice
import com.google.inject.Inject
import io.typefox.lsapi.InitializeParamsImpl
import io.typefox.lsapi.NotificationCallback
import io.typefox.lsapi.PublishDiagnosticsParams
import java.io.File
import java.io.FileWriter
import java.util.List
import org.eclipse.xtend.lib.annotations.Accessors
import org.eclipse.xtext.ide.server.LanguageServerImpl
import org.eclipse.xtext.ide.server.ServerModule
import org.eclipse.xtext.ide.tests.testlanguage.TestLanguageStandaloneSetup
import org.eclipse.xtext.resource.FileExtensionProvider
import org.eclipse.xtext.resource.IResourceServiceProvider
import org.junit.Before
import org.junit.Test
import static org.junit.Assert.*
/**
* @author Sven Efftinge - Initial contribution and API
*/
class ServerTest implements NotificationCallback<PublishDiagnosticsParams> {
@Before
def void setup() {
val injector = Guice.createInjector(new ServerModule())
injector.injectMembers(this)
}
@Inject def voidRegisterTestLanguage(IResourceServiceProvider.Registry registry) {
val injector = new TestLanguageStandaloneSetup().createInjectorAndDoEMFRegistration
registry.extensionToFactoryMap.put(injector.getInstance(FileExtensionProvider).primaryFileExtension, injector.getInstance(IResourceServiceProvider))
}
@Inject LanguageServerImpl languageServer
@Test
def void testInitializeBuild() {
'MyType1.testlang' -> '''
type Test {
string foo
}
'''
languageServer.getTextDocumentService.onPublishDiagnostics(this)
languageServer.initialize(new InitializeParamsImpl => [
rootPath = root.absolutePath
])
assertTrue(diagnosticNotifications.join(','), diagnosticNotifications.isEmpty)
}
@Test
def void testInitializeBuildWithError() {
'MyType1.testlang' -> '''
type Test {
NonExisting foo
}
'''
languageServer.getTextDocumentService.onPublishDiagnostics(this)
languageServer.initialize(new InitializeParamsImpl => [
rootPath = root.absolutePath
])
assertEquals("Couldn't resolve reference to Type 'NonExisting'.", diagnosticNotifications.head.diagnostics.head.message)
}
// utilities
val File root = new File("./test-data/test-project") => [
mkdirs
deleteOnExit
]
def void ->(String path, CharSequence contents) {
val file = new File(root, path)
file.parentFile.mkdirs
file.createNewFile
new FileWriter(file) => [
write(contents.toString)
close
]
}
List<PublishDiagnosticsParams> diagnosticNotifications = newArrayList()
override onNotification(PublishDiagnosticsParams t) {
diagnosticNotifications += t
}
}