Made LanguageServerImpl to implement all four service interfaces. Introduced WorkspaceManager

This commit is contained in:
Sven Efftinge 2016-05-24 17:41:11 +02:00
parent 50628b457f
commit ba6a21b00c
7 changed files with 306 additions and 244 deletions

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 io.typefox.lsapi.Position
import org.eclipse.xtend.lib.annotations.Data
import java.util.List
import io.typefox.lsapi.TextDocumentContentChangeEvent
/**
* @author Sven Efftinge - Initial contribution and API
*/
@Data class Document {
int version
String contents
def int getOffSet(Position position) {
val l = contents.length
val char NL = '\n'
var line = 0
var column = 0
for (var i = 0; i < l; i++) {
val ch = contents.charAt(i)
if (ch === NL) {
line++
column = 0
} else {
column++
}
if (position.line === line && position.character === column) {
return i
}
}
throw new IndexOutOfBoundsException(position.toString + " text was : "+contents)
}
def Document applyChanges(List<? extends TextDocumentContentChangeEvent> changes) {
var newContent = contents
for (change : changes) {
val start = getOffSet(change.range.start)
val end = getOffSet(change.range.end)
newContent = newContent.substring(0, start) + change.text + newContent.substring(end)
}
return new Document(version + 1, newContent)
}
}

View file

@ -13,7 +13,7 @@ import com.google.inject.ImplementedBy
import java.io.File
/**
* @author efftinge - Initial contribution and API
* @author Sven Efftinge - Initial contribution and API
*/
@ImplementedBy(JavaIoFileSystemScanner)
interface IFileSystemScanner {

View file

@ -8,28 +8,62 @@
package org.eclipse.xtext.ide.server
import com.google.inject.Inject
import com.google.inject.Provider
import io.typefox.lsapi.CodeActionParams
import io.typefox.lsapi.CodeLens
import io.typefox.lsapi.CodeLensParams
import io.typefox.lsapi.CompletionItem
import io.typefox.lsapi.CompletionOptionsImpl
import io.typefox.lsapi.Diagnostic
import io.typefox.lsapi.DiagnosticImpl
import io.typefox.lsapi.DidChangeConfigurationParams
import io.typefox.lsapi.DidChangeTextDocumentParams
import io.typefox.lsapi.DidChangeWatchedFilesParams
import io.typefox.lsapi.DidCloseTextDocumentParams
import io.typefox.lsapi.DidOpenTextDocumentParams
import io.typefox.lsapi.DidSaveTextDocumentParams
import io.typefox.lsapi.DocumentFormattingParams
import io.typefox.lsapi.DocumentOnTypeFormattingParams
import io.typefox.lsapi.DocumentRangeFormattingParams
import io.typefox.lsapi.DocumentSymbolParams
import io.typefox.lsapi.InitializeParams
import io.typefox.lsapi.InitializeResult
import io.typefox.lsapi.InitializeResultImpl
import io.typefox.lsapi.LanguageServer
import io.typefox.lsapi.MessageParams
import io.typefox.lsapi.NotificationCallback
import io.typefox.lsapi.PositionImpl
import io.typefox.lsapi.PublishDiagnosticsParams
import io.typefox.lsapi.PublishDiagnosticsParamsImpl
import io.typefox.lsapi.RangeImpl
import io.typefox.lsapi.ReferenceParams
import io.typefox.lsapi.RenameParams
import io.typefox.lsapi.ServerCapabilitiesImpl
import io.typefox.lsapi.ShowMessageRequestParams
import io.typefox.lsapi.TextDocumentPositionParams
import io.typefox.lsapi.TextDocumentService
import io.typefox.lsapi.WindowService
import io.typefox.lsapi.WorkspaceService
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.validation.Issue
/**
*
* @author Sven Efftinge - Initial contribution and API
*/
@Accessors class LanguageServerImpl implements LanguageServer {
@Accessors class LanguageServerImpl implements LanguageServer, WorkspaceService, WindowService, TextDocumentService {
InitializeParams params
@Inject WorkspaceServiceImpl workspaceService
@Inject TextDocumentServiceImpl textDocumentService
@Inject WindowServiceImpl windowService
@Inject Provider<WorkspaceManager> workspaceManagerProvider
WorkspaceManager workspaceManager
override InitializeResult initialize(InitializeParams params) {
this.params = params
workspaceService.initialize(params, [ textDocumentService.publishDiagnostics($0, $1) ])
workspaceManager = workspaceManagerProvider.get
workspaceManager.initialize(URI.createFileURI(params.rootPath), [ this.publishDiagnostics($0, $1) ])
return new InitializeResultImpl => [
capabilities = new ServerCapabilitiesImpl => [
completionProvider = new CompletionOptionsImpl => [
@ -39,23 +73,166 @@ import org.eclipse.xtend.lib.annotations.Accessors
]
]
}
override exit() {
}
override void shutdown() {
}
override getTextDocumentService() {
textDocumentService
this
}
override getWorkspaceService() {
workspaceService
this
}
override getWindowService() {
this
}
override exit() {
// file/content change events
override didOpen(DidOpenTextDocumentParams params) {
workspaceManager.didOpen(params)
}
override didChange(DidChangeTextDocumentParams params) {
workspaceManager.didChange(params)
}
override didClose(DidCloseTextDocumentParams params) {
workspaceManager.didClose(params)
}
override didSave(DidSaveTextDocumentParams params) {
workspaceManager.didSave(params)
}
override didChangeWatchedFiles(DidChangeWatchedFilesParams params) {
workspaceManager.didChangeWatchedFiles(params)
}
// end file/content change events
// validation stuff
private List<NotificationCallback<PublishDiagnosticsParams>> diagnosticListeners = newArrayList()
override onPublishDiagnostics(NotificationCallback<PublishDiagnosticsParams> callback) {
diagnosticListeners.add(callback)
}
private def void publishDiagnostics(URI uri, Iterable<? extends Issue> issues) {
val diagnostics = new PublishDiagnosticsParamsImpl => [
it.uri = workspaceManager.toPath(uri)
it.diagnostics = issues.map[toDiagnostic].toList
]
for (diagnosticsCallback : diagnosticListeners) {
diagnosticsCallback.call(diagnostics)
}
}
private def DiagnosticImpl 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
]
]
]
}
// end validation stuff
override symbol(WorkspaceSymbolParams params) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override getWindowService() {
override didChangeConfiguraton(DidChangeConfigurationParams params) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override onShowMessage(NotificationCallback<MessageParams> callback) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override onShowMessageRequest(NotificationCallback<ShowMessageRequestParams> callback) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override onLogMessage(NotificationCallback<MessageParams> callback) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override completion(TextDocumentPositionParams position) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override resolveCompletionItem(CompletionItem unresolved) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override hover(TextDocumentPositionParams position) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override signatureHelp(TextDocumentPositionParams position) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override definition(TextDocumentPositionParams position) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override references(ReferenceParams params) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override documentHighlight(TextDocumentPositionParams position) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override documentSymbol(DocumentSymbolParams params) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override codeAction(CodeActionParams params) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override codeLens(CodeLensParams params) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override resolveCodeLens(CodeLens unresolved) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override formatting(DocumentFormattingParams params) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override rangeFormatting(DocumentRangeFormattingParams params) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override onTypeFormatting(DocumentOnTypeFormattingParams params) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override rename(RenameParams params) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}

View file

@ -1,158 +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.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
import io.typefox.lsapi.CompletionItem
import io.typefox.lsapi.ReferenceParams
import io.typefox.lsapi.DocumentSymbolParams
import io.typefox.lsapi.CodeActionParams
import io.typefox.lsapi.CodeLensParams
import io.typefox.lsapi.CodeLens
import io.typefox.lsapi.DocumentFormattingParams
import io.typefox.lsapi.DocumentRangeFormattingParams
import io.typefox.lsapi.DocumentOnTypeFormattingParams
import io.typefox.lsapi.RenameParams
import io.typefox.lsapi.DidOpenTextDocumentParams
import io.typefox.lsapi.DidChangeTextDocumentParams
import io.typefox.lsapi.DidCloseTextDocumentParams
import io.typefox.lsapi.DidSaveTextDocumentParams
/**
* @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.call(diagnostics)
}
}
private def DiagnosticImpl 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)
}
override resolveCompletionItem(CompletionItem unresolved) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override hover(TextDocumentPositionParams position) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override signatureHelp(TextDocumentPositionParams position) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override definition(TextDocumentPositionParams position) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override references(ReferenceParams params) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override documentHighlight(TextDocumentPositionParams position) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override documentSymbol(DocumentSymbolParams params) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override codeAction(CodeActionParams params) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override codeLens(CodeLensParams params) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override resolveCodeLens(CodeLens unresolved) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override formatting(DocumentFormattingParams params) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override rangeFormatting(DocumentRangeFormattingParams params) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override onTypeFormatting(DocumentOnTypeFormattingParams params) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override rename(RenameParams params) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override didOpen(DidOpenTextDocumentParams params) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override didChange(DidChangeTextDocumentParams params) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override didClose(DidCloseTextDocumentParams params) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override didSave(DidSaveTextDocumentParams params) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
}

View file

@ -1,32 +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.server
import io.typefox.lsapi.WindowService
import io.typefox.lsapi.NotificationCallback
import io.typefox.lsapi.MessageParams
import io.typefox.lsapi.ShowMessageRequestParams
/**
* @author efftinge - Initial contribution and API
*/
class WindowServiceImpl implements WindowService {
override onShowMessage(NotificationCallback<MessageParams> callback) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override onShowMessageRequest(NotificationCallback<ShowMessageRequestParams> callback) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override onLogMessage(NotificationCallback<MessageParams> callback) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
}

View file

@ -9,13 +9,14 @@ 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.DidChangeTextDocumentParams
import io.typefox.lsapi.DidChangeWatchedFilesParams
import io.typefox.lsapi.DidCloseTextDocumentParams
import io.typefox.lsapi.DidOpenTextDocumentParams
import io.typefox.lsapi.DidSaveTextDocumentParams
import io.typefox.lsapi.FileEvent
import io.typefox.lsapi.InitializeParams
import io.typefox.lsapi.WorkspaceService
import io.typefox.lsapi.WorkspaceSymbolParams
import java.util.List
import java.util.Map
import org.eclipse.emf.common.util.URI
import org.eclipse.xtext.build.BuildRequest
import org.eclipse.xtext.build.IncrementalBuilder
@ -28,73 +29,92 @@ import org.eclipse.xtext.resource.impl.ResourceDescriptionsData
import org.eclipse.xtext.validation.Issue
/**
* @author efftinge - Initial contribution and API
* @author Sven Efftinge - Initial contribution and API
*/
class WorkspaceServiceImpl implements WorkspaceService {
@Inject
protected IncrementalBuilder incrementalBuilder
class WorkspaceManager {
@Inject
protected Provider<XtextResourceSet> resourceSetProvider
@Inject
protected IResourceServiceProvider.Registry languagesRegistry
protected IndexState indexState = new IndexState
@Inject IFileSystemScanner fileSystemScanner
@Inject protected IncrementalBuilder incrementalBuilder
@Inject protected Provider<XtextResourceSet> resourceSetProvider
@Inject protected IResourceServiceProvider.Registry languagesRegistry
@Inject protected IFileSystemScanner fileSystemScanner
IndexState indexState = new IndexState
URI baseDir
(URI, Iterable<Issue>)=>void issueAcceptor
public def void initialize(InitializeParams params, (URI, Iterable<Issue>)=>void acceptor) {
Map<URI, Document> openDocuments = newHashMap()
def void initialize(URI baseDir, (URI, Iterable<Issue>)=>void acceptor) {
val uris = newArrayList
this.baseDir = URI.createFileURI(params.rootPath)
this.baseDir = baseDir
this.issueAcceptor = acceptor
fileSystemScanner.scan(URI.createFileURI(params.rootPath)) [uris += it]
val result = incrementalBuilder.build(newBuildRequest(uris, emptyList),[languagesRegistry.getResourceServiceProvider(it)])
indexState = result.indexState
this.fileSystemScanner.scan(baseDir)[uris += it]
doBuild(uris, emptyList)
}
override didChangeConfiguraton(DidChangeConfigurationParams param) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
}
override didChangeWatchedFiles(DidChangeWatchedFilesParams fileChanges) {
def didChangeWatchedFiles(DidChangeWatchedFilesParams fileChanges) {
val dirtyFiles = newArrayList
val deletedFiles = newArrayList
for (fileEvent : fileChanges.changes) {
if (fileEvent.type === FileEvent.TYPE_DELETED) {
deletedFiles += URI.createFileURI(fileEvent.uri)
deletedFiles += toUri(fileEvent.uri)
} else {
dirtyFiles += URI.createFileURI(fileEvent.uri)
dirtyFiles += toUri(fileEvent.uri)
}
}
val result = incrementalBuilder.build(newBuildRequest(dirtyFiles, deletedFiles),[languagesRegistry.getResourceServiceProvider(it)])
doBuild(dirtyFiles, deletedFiles)
}
def void doBuild(List<URI> dirtyFiles, List<URI> deletedFiles) {
val result = incrementalBuilder.build(newBuildRequest(dirtyFiles, deletedFiles), [
languagesRegistry.getResourceServiceProvider(it)
])
indexState = result.indexState
}
override symbol(WorkspaceSymbolParams param) {
throw new UnsupportedOperationException("TODO: auto-generated method stub")
def didChange(DidChangeTextDocumentParams changeEvent) {
val uri = toUri(changeEvent.textDocument.uri)
val contents = openDocuments.get(uri)
openDocuments.put(uri, contents.applyChanges(changeEvent.contentChanges))
doBuild(#[uri], newArrayList)
}
def didOpen(DidOpenTextDocumentParams changeEvent) {
val uri = toUri(changeEvent.textDocument.uri)
openDocuments.put(uri, new Document(changeEvent.textDocument.version, changeEvent.textDocument.text))
}
def URI toUri(String path) {
URI.createURI(baseDir.toString + path)
}
def toPath(org.eclipse.emf.common.util.URI uri) {
uri.toString.substring(baseDir.toString.length)
}
def didClose(DidCloseTextDocumentParams changeEvent) {
val uri = toUri(changeEvent.textDocument.uri)
openDocuments.remove(uri)
}
def didSave(DidSaveTextDocumentParams changeEvent) {
// do nothing for now
}
protected def BuildRequest newBuildRequest(List<URI> changedFiles, List<URI> deletedFiles) {
new BuildRequest => [
it.baseDir = baseDir
it.resourceSet = createFreshResourceSet(new ResourceDescriptionsData(emptyList))
it.state = new IndexState(indexState.resourceDescriptions.copy, indexState.fileMappings.copy)
it.resourceSet = createFreshResourceSet(state.resourceDescriptions)
it. dirtyFiles = changedFiles
it.dirtyFiles = changedFiles
it.deletedFiles = deletedFiles
afterValidate = [ uri, issues|
afterValidate = [ uri, issues |
issueAcceptor.apply(uri, issues)
return true
]
]
}
protected def XtextResourceSet createFreshResourceSet(ResourceDescriptionsData newIndex) {
resourceSetProvider.get => [
val projectDescription = new ProjectDescription => [
@ -106,4 +126,6 @@ class WorkspaceServiceImpl implements WorkspaceService {
]
}
}
}

View file

@ -55,7 +55,7 @@ class AbstractLanguageServerTest implements NotificationCallback<PublishDiagnost
write(contents.toString)
close
]
return file.absolutePath
return file.absolutePath.substring(root.absolutePath.length)
}
override call(PublishDiagnosticsParams t) {