Skip to content

Commit

Permalink
Merge pull request #1372 from TypeFox/language-server
Browse files Browse the repository at this point in the history
Language server
  • Loading branch information
Evgen Vidolob committed May 27, 2016
2 parents 500bd65 + 3f15489 commit f686314
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import com.google.inject.Singleton;
import com.google.web.bindery.event.shared.EventBus;

import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.ide.api.editor.EditorRegistry;
import org.eclipse.che.ide.api.event.FileEvent;
import org.eclipse.che.ide.api.event.FileEventHandler;
Expand Down Expand Up @@ -37,27 +39,34 @@ protected void configureFileTypes(FileTypeRegistry fileTypeRegistry, LanguageSer
// would listen on messages when new language servers get registered.
FileType fileType = new FileType(resources.file(), "foo");
fileTypeRegistry.registerFileType(fileType);
FileType fileType2 = new FileType(resources.file(), "testlang");
fileTypeRegistry.registerFileType(fileType2);
// register editor provider
editorRegistry.registerDefaultEditor(fileType, editorProvider);
editorRegistry.registerDefaultEditor(fileType2, editorProvider);
}

@Inject
protected void registerFileEventHandler(EventBus eventBus, final TextDocumentServiceClient serviceClient, final DtoFactory dtoFactory) {
eventBus.addHandler(FileEvent.TYPE, new FileEventHandler() {

@Override
public void onFileOperation(FileEvent event) {
TextDocumentIdentifierDTO documentId = dtoFactory.createDto(TextDocumentIdentifierDTO.class);
public void onFileOperation(final FileEvent event) {
final TextDocumentIdentifierDTO documentId = dtoFactory.createDto(TextDocumentIdentifierDTO.class);
documentId.setUri(event.getFile().getPath());
switch (event.getOperationType()) {
case OPEN:
DidOpenTextDocumentParamsDTO openEvent = dtoFactory.createDto(DidOpenTextDocumentParamsDTO.class);
TextDocumentItemDTO documentItem = dtoFactory.createDto(TextDocumentItemDTO.class);
documentItem.setUri(event.getFile().getPath());
documentItem.setVersion(LanguageServerEditorConfiguration.INITIAL_DOCUMENT_VERSION);
//TODO send text?
openEvent.setTextDocument(documentItem);
serviceClient.didOpen(openEvent);
event.getFile().getContent().then(new Operation<String>() {
@Override
public void apply(String text) throws OperationException {
DidOpenTextDocumentParamsDTO openEvent = dtoFactory.createDto(DidOpenTextDocumentParamsDTO.class);
TextDocumentItemDTO documentItem = dtoFactory.createDto(TextDocumentItemDTO.class);
documentItem.setUri(event.getFile().getPath());
documentItem.setVersion(LanguageServerEditorConfiguration.INITIAL_DOCUMENT_VERSION);
documentItem.setText(text);
openEvent.setTextDocument(documentItem);
serviceClient.didOpen(openEvent);
}});
break;
case CLOSE:
DidCloseTextDocumentParamsDTO closeEvent = dtoFactory.createDto(DidCloseTextDocumentParamsDTO.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public void onDocumentChange(DocumentChangeEvent event) {
private void handleDocumentChange(DocumentChangeEvent event) {
Document document = event.getDocument().getDocument();
TextPosition startPosition = document.getPositionFromIndex(event.getOffset());
TextPosition endPosition = document.getPositionFromIndex(event.getOffset() + event.getLength());
TextPosition endPosition = document.getPositionFromIndex(event.getOffset() + event.getRemoveCharCount());

DidChangeTextDocumentParamsDTO changeDTO = dtoFactory.createDto(DidChangeTextDocumentParamsDTO.class);
String uri = document.getFile().getPath();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,17 @@ public CompletionImpl(CompletionItemDTO completionItem) {
@Override
public void apply(Document document) {
//TODO in general resolve completion item may not provide getTextEdit, need to add checks
RangeDTO range = completionItem.getTextEdit().getRange();
int startOffset = document.getIndexFromPosition(
new TextPosition(range.getStart().getLine(), range.getStart().getCharacter()));
int endOffset = document
.getIndexFromPosition(new TextPosition(range.getEnd().getLine(), range.getEnd().getCharacter()));
document.replace(startOffset, endOffset - startOffset, completionItem.getTextEdit().getNewText());
if (completionItem.getTextEdit() != null) {
RangeDTO range = completionItem.getTextEdit().getRange();
int startOffset = document.getIndexFromPosition(
new TextPosition(range.getStart().getLine(), range.getStart().getCharacter()));
int endOffset = document
.getIndexFromPosition(new TextPosition(range.getEnd().getLine(), range.getEnd().getCharacter()));
document.replace(startOffset, endOffset - startOffset, completionItem.getTextEdit().getNewText());
} else {
String insertText = completionItem.getInsertText()==null?completionItem.getLabel():completionItem.getInsertText();
document.replace(document.getCursorOffset(), 0, insertText);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.eclipse.che.inject.DynaModule;
import org.eclipse.che.plugin.languageserver.server.dummyimpl.FooLanguageServer;
import org.eclipse.che.plugin.languageserver.server.dummyimpl.LanguageServerRegistrant;
import org.eclipse.che.plugin.languageserver.server.lsapi.PublishDiagnosticsParamsMessenger;

import com.google.inject.AbstractModule;
Expand All @@ -14,6 +15,7 @@ protected void configure() {
// HACK LanguageServers should be registered dynamically or at least via
// some configuration.
bind(FooLanguageServer.class);
bind(LanguageServerRegistrant.class);

bind(TextDocumentServiceImpl.class);
bind(PublishDiagnosticsParamsMessenger.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,10 @@ public LanguageServer findServer(String uri) {

public void registerForExtension(String extension, LanguageServer server) {
this.extensionToServer.put(extension, server);
server.initialize(new InitializeParamsImpl() {
{
//HACK hard coded properties
setProcessId(4711);
setRootPath("/projects/");
}
});
InitializeParamsImpl initializeParams = new InitializeParamsImpl();
initializeParams.setProcessId(4711);
initializeParams.setRootPath("/projects/");
server.initialize(initializeParams);
server.getTextDocumentService().onPublishDiagnostics(new NotificationCallback<PublishDiagnosticsParams>() {
@Override
public void call(PublishDiagnosticsParams param) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,17 @@ public class TextDocumentServiceImpl {
public TextDocumentServiceImpl(LanguageServerRegistry languageServerRegistry) {
this.languageServerRegistry = languageServerRegistry;
}

private String prefixURI(String relativePath) {
return "file:///projects"+relativePath;
}

@POST
@Path("completion")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public List<? extends CompletionItem> completion(TextDocumentPositionParamsDTO textDocumentPositionParams) {
textDocumentPositionParams.getTextDocument().setUri(prefixURI(textDocumentPositionParams.getTextDocument().getUri()));
LanguageServer server = getServer(textDocumentPositionParams.getTextDocument().getUri());
List<? extends CompletionItem> completion = server.getTextDocumentService()
.completion(textDocumentPositionParams);
Expand All @@ -60,6 +65,7 @@ public CompletionItem resolveCompletionItem(CompletionItemDTO unresolved) {
@Path("didChange")
@Consumes(MediaType.APPLICATION_JSON)
public void didChange(DidChangeTextDocumentParamsDTO change) {
change.getTextDocument().setUri(prefixURI(change.getTextDocument().getUri()));
LanguageServer server = getServer(change.getTextDocument().getUri());
server.getTextDocumentService().didChange(change);
}
Expand All @@ -68,6 +74,7 @@ public void didChange(DidChangeTextDocumentParamsDTO change) {
@Path("didOpen")
@Consumes(MediaType.APPLICATION_JSON)
public void didOpen(DidOpenTextDocumentParamsDTO openEvent) {
openEvent.getTextDocument().setUri(prefixURI(openEvent.getTextDocument().getUri()));
LanguageServer server = getServer(openEvent.getTextDocument().getUri());
server.getTextDocumentService().didOpen(openEvent);
}
Expand All @@ -76,6 +83,7 @@ public void didOpen(DidOpenTextDocumentParamsDTO openEvent) {
@Path("didClose")
@Consumes(MediaType.APPLICATION_JSON)
public void didClose(DidCloseTextDocumentParamsDTO closeEvent) {
closeEvent.getTextDocument().setUri(prefixURI(closeEvent.getTextDocument().getUri()));
LanguageServer server = getServer(closeEvent.getTextDocument().getUri());
server.getTextDocumentService().didClose(closeEvent);
}
Expand All @@ -84,6 +92,7 @@ public void didClose(DidCloseTextDocumentParamsDTO closeEvent) {
@Path("didSave")
@Consumes(MediaType.APPLICATION_JSON)
public void didSave(DidSaveTextDocumentParamsDTO saveEvent) {
saveEvent.getTextDocument().setUri(prefixURI(saveEvent.getTextDocument().getUri()));
LanguageServer server = getServer(saveEvent.getTextDocument().getUri());
server.getTextDocumentService().didSave(saveEvent);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package org.eclipse.che.plugin.languageserver.server.dummyimpl;

import java.io.File;
import java.io.IOException;
import java.lang.ProcessBuilder.Redirect;
import java.util.HashSet;
import java.util.Set;

import org.eclipse.che.plugin.languageserver.server.LanguageServerRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.inject.Inject;
import com.google.inject.Singleton;

import io.typefox.lsapi.json.JsonBasedLanguageServer;

@Singleton
public class LanguageServerRegistrant {

private final static Logger LOG = LoggerFactory.getLogger(LanguageServerRegistrant.class);

private final static String JAVA_EXEC = System.getProperty("java.home")+"/bin/java";

@Inject
public void registerLanguageServer(LanguageServerRegistry registry) {
Runnable runnable = new Runnable() {

@Override
public void run() {
String suffix = "-languageserver.jar";
Set<String> successfullyRegistered = new HashSet<>();
while (true) {
for (File file : new File("/projects").listFiles()) {
if (file.getName().endsWith(suffix)) {
if (successfullyRegistered.add(file.getName())) {
try {
ProcessBuilder languageServerStarter = new ProcessBuilder(JAVA_EXEC, "-jar", file.getAbsolutePath(), "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=1044", "debug");
languageServerStarter.redirectInput(Redirect.PIPE);
languageServerStarter.redirectOutput(Redirect.PIPE);
Process process = languageServerStarter.start();
JsonBasedLanguageServer languageServer = new JsonBasedLanguageServer();
languageServer.connect(process.getInputStream(), process.getOutputStream());
String name = file.getName();
String[] extensions = name.substring(0, name.length() - suffix.length()).split("-");
for (int i = 0; i < extensions.length; i++) {
String extension = extensions[i];
registry.registerForExtension(extension, languageServer);
LOG.info("Registered language server for extension '"+extension+"'.");
}
} catch (IOException e) {
successfullyRegistered.remove(file.getName());
LOG.error(e.getMessage(), e);
}
}
}
}
try {
Thread.sleep(10_000L);
} catch (InterruptedException e) {
LOG.error(e.getMessage(), e);
}
}
}

};
new Thread(runnable).start();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.google.gson.Gson;

import io.typefox.lsapi.PublishDiagnosticsParams;
import io.typefox.lsapi.PublishDiagnosticsParamsImpl;

@Singleton
public class PublishDiagnosticsParamsMessenger implements EventSubscriber<PublishDiagnosticsParams> {
Expand All @@ -32,6 +33,9 @@ public PublishDiagnosticsParamsMessenger(final EventService eventService) {

public void onEvent(final PublishDiagnosticsParams event) {
try {
if (event instanceof PublishDiagnosticsParamsImpl && event.getUri().startsWith("file:///projects")) {
((PublishDiagnosticsParamsImpl)event).setUri(event.getUri().substring(16));
}
final ChannelBroadcastMessage bm = new ChannelBroadcastMessage();
bm.setChannel("languageserver/textDocument/publishDiagnostics");
bm.setBody(new Gson().toJson(event));
Expand Down

0 comments on commit f686314

Please sign in to comment.