mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-16 08:48:55 +00:00
[lsp] made workspace manager more independent of LSP
This commit is contained in:
parent
3cf774385d
commit
cea7256665
8 changed files with 173 additions and 58 deletions
|
@ -8,9 +8,8 @@
|
|||
package org.eclipse.xtext.ide.server
|
||||
|
||||
import io.typefox.lsapi.Position
|
||||
import io.typefox.lsapi.TextEdit
|
||||
import org.eclipse.xtend.lib.annotations.Data
|
||||
import java.util.List
|
||||
import io.typefox.lsapi.TextDocumentContentChangeEvent
|
||||
|
||||
/**
|
||||
* @author Sven Efftinge - Initial contribution and API
|
||||
|
@ -43,12 +42,12 @@ import io.typefox.lsapi.TextDocumentContentChangeEvent
|
|||
throw new IndexOutOfBoundsException(position.toString + " text was : "+contents)
|
||||
}
|
||||
|
||||
def Document applyChanges(List<? extends TextDocumentContentChangeEvent> changes) {
|
||||
def Document applyChanges(Iterable<? extends TextEdit> 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)
|
||||
newContent = newContent.substring(0, start) + change.newText + newContent.substring(end)
|
||||
}
|
||||
return new Document(version + 1, newContent)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*******************************************************************************
|
||||
* 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.PositionImpl
|
||||
import io.typefox.lsapi.RangeImpl
|
||||
|
||||
/**
|
||||
* @author Sven Efftinge - Initial contribution and API
|
||||
*/
|
||||
class LSPExtensions {
|
||||
|
||||
|
||||
static def PositionImpl newPosition(int line, int character) {
|
||||
new PositionImpl => [
|
||||
it.line = line
|
||||
it.character = character
|
||||
]
|
||||
}
|
||||
|
||||
static def RangeImpl newRange(PositionImpl start, PositionImpl end) {
|
||||
new RangeImpl => [
|
||||
it.start = start
|
||||
it.end = end
|
||||
]
|
||||
}
|
||||
}
|
|
@ -26,6 +26,7 @@ import io.typefox.lsapi.DocumentFormattingParams
|
|||
import io.typefox.lsapi.DocumentOnTypeFormattingParams
|
||||
import io.typefox.lsapi.DocumentRangeFormattingParams
|
||||
import io.typefox.lsapi.DocumentSymbolParams
|
||||
import io.typefox.lsapi.FileEvent
|
||||
import io.typefox.lsapi.InitializeParams
|
||||
import io.typefox.lsapi.InitializeResult
|
||||
import io.typefox.lsapi.InitializeResultImpl
|
||||
|
@ -42,6 +43,7 @@ import io.typefox.lsapi.ServerCapabilitiesImpl
|
|||
import io.typefox.lsapi.ShowMessageRequestParams
|
||||
import io.typefox.lsapi.TextDocumentPositionParams
|
||||
import io.typefox.lsapi.TextDocumentService
|
||||
import io.typefox.lsapi.TextEditImpl
|
||||
import io.typefox.lsapi.WindowService
|
||||
import io.typefox.lsapi.WorkspaceService
|
||||
import io.typefox.lsapi.WorkspaceSymbolParams
|
||||
|
@ -59,9 +61,11 @@ import org.eclipse.xtext.validation.Issue
|
|||
InitializeParams params
|
||||
@Inject Provider<WorkspaceManager> workspaceManagerProvider
|
||||
WorkspaceManager workspaceManager
|
||||
String rootPath
|
||||
|
||||
override InitializeResult initialize(InitializeParams params) {
|
||||
this.params = params
|
||||
this.rootPath = URI.createFileURI(params.rootPath).toString
|
||||
workspaceManager = workspaceManagerProvider.get
|
||||
workspaceManager.initialize(URI.createFileURI(params.rootPath), [ this.publishDiagnostics($0, $1) ])
|
||||
return new InitializeResultImpl => [
|
||||
|
@ -92,26 +96,48 @@ import org.eclipse.xtext.validation.Issue
|
|||
|
||||
// file/content change events
|
||||
override didOpen(DidOpenTextDocumentParams params) {
|
||||
workspaceManager.didOpen(params)
|
||||
workspaceManager.didOpen(params.textDocument.uri.toUri, params.textDocument.version, params.textDocument.text)
|
||||
}
|
||||
|
||||
override didChange(DidChangeTextDocumentParams params) {
|
||||
workspaceManager.didChange(params)
|
||||
workspaceManager.didChange(params.textDocument.uri.toUri, params.textDocument.version, params.contentChanges.map [ event |
|
||||
val edit = new TextEditImpl
|
||||
edit.range = event.range as RangeImpl
|
||||
edit.newText = event.text
|
||||
return edit
|
||||
])
|
||||
}
|
||||
|
||||
override didClose(DidCloseTextDocumentParams params) {
|
||||
workspaceManager.didClose(params)
|
||||
workspaceManager.didClose(params.textDocument.uri.toUri)
|
||||
}
|
||||
|
||||
override didSave(DidSaveTextDocumentParams params) {
|
||||
workspaceManager.didSave(params)
|
||||
workspaceManager.didSave(params.textDocument.uri.toUri)
|
||||
}
|
||||
|
||||
override didChangeWatchedFiles(DidChangeWatchedFilesParams params) {
|
||||
workspaceManager.didChangeWatchedFiles(params)
|
||||
val dirtyFiles = newArrayList
|
||||
val deletedFiles = newArrayList
|
||||
for (fileEvent : params.changes) {
|
||||
if (fileEvent.type === FileEvent.TYPE_DELETED) {
|
||||
deletedFiles += toUri(fileEvent.uri)
|
||||
} else {
|
||||
dirtyFiles += toUri(fileEvent.uri)
|
||||
}
|
||||
}
|
||||
workspaceManager.doBuild(dirtyFiles, deletedFiles)
|
||||
}
|
||||
// end file/content change events
|
||||
|
||||
def URI toUri(String path) {
|
||||
URI.createURI(rootPath + path)
|
||||
}
|
||||
|
||||
def toPath(URI uri) {
|
||||
uri.toString.substring(rootPath.length)
|
||||
}
|
||||
|
||||
// validation stuff
|
||||
|
||||
private List<NotificationCallback<PublishDiagnosticsParams>> diagnosticListeners = newArrayList()
|
||||
|
@ -122,7 +148,7 @@ import org.eclipse.xtext.validation.Issue
|
|||
|
||||
private def void publishDiagnostics(URI uri, Iterable<? extends Issue> issues) {
|
||||
val diagnostics = new PublishDiagnosticsParamsImpl => [
|
||||
it.uri = workspaceManager.toPath(uri)
|
||||
it.uri = toPath(uri)
|
||||
it.diagnostics = issues.map[toDiagnostic].toList
|
||||
]
|
||||
for (diagnosticsCallback : diagnosticListeners) {
|
||||
|
|
|
@ -10,22 +10,21 @@ package org.eclipse.xtext.ide.server
|
|||
import com.google.inject.Inject
|
||||
import com.google.inject.Provider
|
||||
import java.util.List
|
||||
import java.util.Map
|
||||
import org.eclipse.emf.common.util.URI
|
||||
import org.eclipse.emf.ecore.resource.Resource
|
||||
import org.eclipse.xtext.build.BuildRequest
|
||||
import org.eclipse.xtext.build.IncrementalBuilder
|
||||
import org.eclipse.xtext.build.IncrementalBuilder.Result
|
||||
import org.eclipse.xtext.build.IndexState
|
||||
import org.eclipse.xtext.resource.IExternalContentSupport
|
||||
import org.eclipse.xtext.resource.IExternalContentSupport.IExternalContentProvider
|
||||
import org.eclipse.xtext.resource.IResourceDescription
|
||||
import org.eclipse.xtext.resource.IResourceServiceProvider
|
||||
import org.eclipse.xtext.resource.XtextResourceSet
|
||||
import org.eclipse.xtext.resource.impl.ChunkedResourceDescriptions
|
||||
import org.eclipse.xtext.resource.impl.ProjectDescription
|
||||
import org.eclipse.xtext.resource.impl.ResourceDescriptionsData
|
||||
import org.eclipse.xtext.validation.Issue
|
||||
import java.util.Map
|
||||
import org.eclipse.xtext.build.IncrementalBuilder.Result
|
||||
import org.eclipse.emf.ecore.resource.Resource
|
||||
|
||||
/**
|
||||
* @author Sven Efftinge - Initial contribution and API
|
||||
|
@ -92,7 +91,7 @@ class ProjectManager {
|
|||
]
|
||||
}
|
||||
|
||||
def Resource getResource(org.eclipse.emf.common.util.URI uri) {
|
||||
def Resource getResource(URI uri) {
|
||||
resourceSet.getResource(uri, true)
|
||||
}
|
||||
|
||||
|
|
|
@ -9,12 +9,7 @@ package org.eclipse.xtext.ide.server
|
|||
|
||||
import com.google.inject.Inject
|
||||
import com.google.inject.Provider
|
||||
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.TextEdit
|
||||
import java.util.ArrayList
|
||||
import java.util.List
|
||||
import java.util.Map
|
||||
|
@ -60,19 +55,6 @@ class WorkspaceManager {
|
|||
fullIndex.put("DEFAULT", indexResult.indexState.resourceDescriptions)
|
||||
}
|
||||
|
||||
def didChangeWatchedFiles(DidChangeWatchedFilesParams fileChanges) {
|
||||
val dirtyFiles = newArrayList
|
||||
val deletedFiles = newArrayList
|
||||
for (fileEvent : fileChanges.changes) {
|
||||
if (fileEvent.type === FileEvent.TYPE_DELETED) {
|
||||
deletedFiles += toUri(fileEvent.uri)
|
||||
} else {
|
||||
dirtyFiles += toUri(fileEvent.uri)
|
||||
}
|
||||
}
|
||||
doBuild(dirtyFiles, deletedFiles)
|
||||
}
|
||||
|
||||
def void doBuild(List<URI> dirtyFiles, List<URI> deletedFiles) {
|
||||
//TODO sort projects by dependency
|
||||
val allDirty = new ArrayList(dirtyFiles)
|
||||
|
@ -100,38 +82,27 @@ class WorkspaceManager {
|
|||
return baseDir2ProjectManager.get(projectBaseDir)
|
||||
}
|
||||
|
||||
def URI toUri(String path) {
|
||||
URI.createURI(baseDir.toString + path)
|
||||
}
|
||||
|
||||
def toPath(URI uri) {
|
||||
uri.toString.substring(baseDir.toString.length)
|
||||
}
|
||||
|
||||
def didChange(DidChangeTextDocumentParams changeEvent) {
|
||||
val uri = toUri(changeEvent.textDocument.uri)
|
||||
def didChange(URI uri, int version, Iterable<TextEdit> changes) {
|
||||
val contents = openDocuments.get(uri)
|
||||
openDocuments.put(uri, contents.applyChanges(changeEvent.contentChanges))
|
||||
openDocuments.put(uri, contents.applyChanges(changes))
|
||||
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 didOpen(URI uri, int version, String contents) {
|
||||
openDocuments.put(uri, new Document(version, contents))
|
||||
doBuild(#[uri], newArrayList)
|
||||
}
|
||||
|
||||
def didClose(DidCloseTextDocumentParams changeEvent) {
|
||||
val uri = toUri(changeEvent.textDocument.uri)
|
||||
def didClose(URI uri) {
|
||||
openDocuments.remove(uri)
|
||||
doBuild(#[uri], newArrayList)
|
||||
}
|
||||
|
||||
def didSave(DidSaveTextDocumentParams changeEvent) {
|
||||
def didSave(URI uri) {
|
||||
// do nothing for now
|
||||
}
|
||||
|
||||
def <T> void doRead(URI uri, (Document, XtextResource)=>T work) {
|
||||
def <T> T doRead(URI uri, (Document, XtextResource)=>T work) {
|
||||
val projectMnr = getProjectManager(uri)
|
||||
val doc = openDocuments.get(uri)
|
||||
work.apply(doc, projectMnr.getResource(uri) as XtextResource)
|
||||
|
|
|
@ -25,7 +25,7 @@ import org.eclipse.xtext.util.Files
|
|||
import org.junit.Before
|
||||
|
||||
/**
|
||||
* @author efftinge - Initial contribution and API
|
||||
* @author Sven Efftinge - Initial contribution and API
|
||||
*/
|
||||
class AbstractLanguageServerTest implements NotificationCallback<PublishDiagnosticsParams> {
|
||||
|
||||
|
@ -44,8 +44,7 @@ class AbstractLanguageServerTest implements NotificationCallback<PublishDiagnost
|
|||
root.deleteOnExit
|
||||
}
|
||||
|
||||
@Inject
|
||||
protected LanguageServerImpl languageServer
|
||||
@Inject protected LanguageServerImpl languageServer
|
||||
protected Map<String, List<? extends Diagnostic>> diagnostics = newHashMap()
|
||||
|
||||
protected File root
|
||||
|
|
|
@ -9,7 +9,7 @@ package org.eclipse.xtext.ide.tests.server
|
|||
|
||||
import io.typefox.lsapi.PositionImpl
|
||||
import io.typefox.lsapi.RangeImpl
|
||||
import io.typefox.lsapi.TextDocumentContentChangeEventImpl
|
||||
import io.typefox.lsapi.TextEditImpl
|
||||
import org.eclipse.xtext.ide.server.Document
|
||||
import org.junit.Test
|
||||
|
||||
|
@ -97,12 +97,12 @@ class DocumentTest {
|
|||
}
|
||||
|
||||
private def change(PositionImpl startPos, PositionImpl endPos, String newText) {
|
||||
new TextDocumentContentChangeEventImpl => [
|
||||
new TextEditImpl => [
|
||||
range = new RangeImpl => [
|
||||
start = startPos
|
||||
end = endPos
|
||||
]
|
||||
text = newText
|
||||
it.newText = newText
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
/*******************************************************************************
|
||||
* 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 java.io.File
|
||||
import java.io.FileWriter
|
||||
import java.util.List
|
||||
import java.util.Map
|
||||
import org.eclipse.emf.common.util.URI
|
||||
import org.eclipse.xtext.ide.server.ServerModule
|
||||
import org.eclipse.xtext.ide.server.WorkspaceManager
|
||||
import org.eclipse.xtext.ide.tests.testlanguage.TestLanguageStandaloneSetup
|
||||
import org.eclipse.xtext.resource.FileExtensionProvider
|
||||
import org.eclipse.xtext.resource.IResourceServiceProvider
|
||||
import org.eclipse.xtext.util.Files
|
||||
import org.eclipse.xtext.validation.Issue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.Assert
|
||||
|
||||
/**
|
||||
* @author Sven Efftinge - Initial contribution and API
|
||||
*/
|
||||
class WorkspaceManagerTest {
|
||||
|
||||
@Test def void testDoRead() {
|
||||
val path = 'MyType1.testlang' -> '''
|
||||
type Test {
|
||||
string foo
|
||||
}
|
||||
'''
|
||||
|
||||
workspaceManger.doBuild(#[path], emptyList)
|
||||
|
||||
val String inMemContents = '''
|
||||
type Test {
|
||||
Test foo
|
||||
}
|
||||
'''
|
||||
|
||||
workspaceManger.didOpen(path, 1, inMemContents)
|
||||
|
||||
Assert.assertEquals(inMemContents, workspaceManger.doRead(path, [$0.contents]))
|
||||
}
|
||||
|
||||
@Inject protected WorkspaceManager workspaceManger
|
||||
|
||||
@Before
|
||||
def void setup() {
|
||||
val injector = Guice.createInjector(new ServerModule())
|
||||
injector.injectMembers(this)
|
||||
// register notification callbacks
|
||||
// create workingdir
|
||||
root = new File("./test-data/test-project")
|
||||
if (!root.mkdirs) {
|
||||
Files.cleanFolder(root, null, true, false)
|
||||
}
|
||||
root.deleteOnExit
|
||||
workspaceManger.initialize(URI.createFileURI(root.absolutePath), [diagnostics.put($0, $1.toList)])
|
||||
}
|
||||
|
||||
protected Map<URI, List<Issue>> diagnostics = newHashMap()
|
||||
protected File root
|
||||
|
||||
def URI ->(String path, CharSequence contents) {
|
||||
val file = new File(root, path)
|
||||
file.parentFile.mkdirs
|
||||
file.createNewFile
|
||||
new FileWriter(file) => [
|
||||
write(contents.toString)
|
||||
close
|
||||
]
|
||||
return URI.createFileURI(file.absolutePath)
|
||||
}
|
||||
|
||||
@Inject def voidRegisterTestLanguage(IResourceServiceProvider.Registry registry) {
|
||||
val injector = new TestLanguageStandaloneSetup().createInjectorAndDoEMFRegistration
|
||||
registry.extensionToFactoryMap.put(injector.getInstance(FileExtensionProvider).primaryFileExtension,
|
||||
injector.getInstance(IResourceServiceProvider))
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue