Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for using multiple language servers to be registered for the same files #4609 #5442

Merged
merged 20 commits into from
Jul 10, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.eclipse.che.ide.api.editor.text.Position;
import org.eclipse.che.ide.api.editor.text.TextPosition;
import org.eclipse.che.ide.api.editor.text.annotation.Annotation;
import org.eclipse.che.ide.util.loging.Log;

import java.util.ArrayList;
import java.util.Collections;
Expand Down Expand Up @@ -70,6 +71,7 @@ protected void addAnnotation(final Annotation annotation, final Position positio
try {
addPosition(position);
} catch (BadLocationException ignore) {
Log.error(getClass(), "BadLocation for " + annotation);
//ignore invalid location
}
getAnnotationModelEvent().annotationAdded(annotation);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@
import org.eclipse.che.requirejs.ModuleHolder;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
Expand Down Expand Up @@ -687,14 +688,16 @@ public void scrollToLine(int line) {
}

public void showErrors(AnnotationModelEvent event) {
List<Annotation> addedAnnotations = event.getAddedAnnotations();
JsArray<OrionProblemOverlay> jsArray = JsArray.createArray().cast();
AnnotationModel annotationModel = event.getAnnotationModel();
OrionAnnotationSeverityProvider severityProvider = null;
if (annotationModel instanceof OrionAnnotationSeverityProvider) {
severityProvider = (OrionAnnotationSeverityProvider)annotationModel;
}
for (Annotation annotation : addedAnnotations) {

Iterator<Annotation> annotationIterator = annotationModel.getAnnotationIterator();
while (annotationIterator.hasNext()) {
Annotation annotation = annotationIterator.next();
Position position = annotationModel.getPosition(annotation);

OrionProblemOverlay problem = JavaScriptObject.createObject().cast();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import com.google.inject.Singleton;
import org.eclipse.che.api.languageserver.exception.LanguageServerException;
import org.eclipse.che.api.languageserver.launcher.LanguageServerLauncherTemplate;
import org.eclipse.che.api.languageserver.registry.DocumentFilter;
import org.eclipse.che.api.languageserver.registry.LanguageServerDescription;
import org.eclipse.che.commons.lang.IoUtil;
import org.eclipse.che.plugin.csharp.inject.CSharpModule;
import org.eclipse.lsp4j.jsonrpc.Launcher;
Expand All @@ -25,14 +27,18 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;


/**
* @author Evgen Vidolob
*/
@Singleton
public class CSharpLanguageServerLauncher extends LanguageServerLauncherTemplate {
private static final String REGEX = ".*\\.(cs|csx)";


private static final LanguageServerDescription DESCRIPTION = createServerDescription();

private final Path launchScript;

Expand Down Expand Up @@ -81,13 +87,19 @@ protected LanguageServer connectToLanguageServer(final Process languageServerPro
}

@Override
public String getLanguageId() {
return CSharpModule.LANGUAGE_ID;
public LanguageServerDescription getDescription() {
return DESCRIPTION;
}


private static LanguageServerDescription createServerDescription() {
LanguageServerDescription description = new LanguageServerDescription("org.eclipse.che.plugin.csharp.languageserver", null,
Arrays.asList(new DocumentFilter(CSharpModule.LANGUAGE_ID, REGEX, null)));
return description;
}

@Override
public boolean isAbleToLaunch() {
return Files.exists(launchScript);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ protected void configure() {
description.setMimeType(MIME_TYPE);
Multibinder.newSetBinder(binder(), LanguageDescription.class).addBinding().toInstance(description);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.che.api.languageserver.exception.LanguageServerException;
import org.eclipse.che.api.languageserver.launcher.LanguageServerLauncher;
import org.eclipse.che.api.languageserver.launcher.LanguageServerLauncherTemplate;
import org.eclipse.che.api.languageserver.registry.DocumentFilter;
import org.eclipse.che.api.languageserver.registry.LanguageServerDescription;
import org.eclipse.che.api.languageserver.registry.ServerInitializerObserver;
import org.eclipse.che.api.languageserver.shared.model.LanguageDescription;
import org.eclipse.che.plugin.json.inject.JsonModule;
import org.eclipse.lsp4j.ServerCapabilities;
import org.eclipse.lsp4j.jsonrpc.Endpoint;
Expand All @@ -28,15 +30,19 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;


/**
* @author Evgen Vidolob
* @author Anatolii Bazko
*/
@Singleton
public class JsonLanguageServerLauncher extends LanguageServerLauncherTemplate implements ServerInitializerObserver {
private static final String REGEX = ".*\\.(json|bowerrc|jshintrc|jscsrc|eslintrc|babelrc)";
private static final LanguageServerDescription DESCRIPTION = createServerDescription();

private final Path launchScript;

Expand All @@ -45,11 +51,6 @@ public JsonLanguageServerLauncher() {
launchScript = Paths.get(System.getenv("HOME"), "che/ls-json/launch.sh");
}

@Override
public String getLanguageId() {
return JsonModule.LANGUAGE_ID;
}

@Override
public boolean isAbleToLaunch() {
return Files.exists(launchScript);
Expand All @@ -75,7 +76,10 @@ protected Process startLanguageServerProcess(String projectPath) throws Language
}

@Override
public void onServerInitialized(LanguageServer server, ServerCapabilities capabilities, LanguageDescription languageDescription, String projectPath) {
public void onServerInitialized(LanguageServerLauncher launcher,
LanguageServer server,
ServerCapabilities capabilities,
String projectPath) {
Endpoint endpoint = ServiceEndpoints.toEndpoint(server);
JsonExtension serviceObject = ServiceEndpoints.toServiceObject(endpoint, JsonExtension.class);
Map<String, String[]> associations = new HashMap<>();
Expand All @@ -89,4 +93,14 @@ public void onServerInitialized(LanguageServer server, ServerCapabilities capabi
associations.put("/tsconfig.json", new String[]{"http://json.schemastore.org/tsconfig"});
serviceObject.jsonSchemaAssociation(associations);
}

public LanguageServerDescription getDescription() {
return DESCRIPTION;
}

private static LanguageServerDescription createServerDescription() {
LanguageServerDescription description = new LanguageServerDescription("org.eclipse.che.plugin.json.languageserver", null,
Arrays.asList(new DocumentFilter(JsonModule.LANGUAGE_ID, REGEX, null)));
return description;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,9 @@ public LanguageServerFileTypeRegister(LanguageServerRegistryServiceClient server
OrionContentTypeRegistrant contentTypeRegistrant,
OrionHoverRegistrant orionHoverRegistrant,
OrionOccurrencesRegistrant orionOccurrencesRegistrant,
LanguageServerEditorProvider editorProvider,
LanguageServerEditorProvider editorProvider,
HoverProvider hoverProvider,
OccurrencesProvider occurrencesProvider) {
OccurrencesProvider occurrencesProvider) {
this.serverLanguageRegistry = serverLanguageRegistry;
this.lsRegistry = lsRegistry;
this.resources = resources;
Expand Down Expand Up @@ -97,6 +97,7 @@ public void apply(List<LanguageDescription> langs) throws OperationException {
final FileType fileType = new FileType(resources.file(), null, RegExp.quote(fileName));
lsRegistry.registerFileType(fileType, lang);
editorRegistry.registerDefaultEditor(fileType, editorProvider);

}
String mimeType = lang.getMimeType();
contentTypes.push(mimeType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,24 @@ public interface DiagnosticCollector {
/**
* Notification of a diagnostic.
*
* @param diagnosticsCollection an identifier for the set of diagnostics the reported diagnostic belongs to.
* @param diagnostic
* Diagnostic - The discovered diagnostic.
*/
void acceptDiagnostic(Diagnostic diagnostic);
void acceptDiagnostic(String diagnosticsCollection, Diagnostic diagnostic);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add description what diagnosticsCollection parameter mean

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, not clear


/**
* Notification sent before starting the diagnostic process.
* Typically, this would tell a diagnostic collector to clear previously recorded diagnostic.
* Notification sent before starting the reporting of a collection of diagnostics
* Typically, this would tell a diagnostic collector to clear previously recorded diagnostics in the same collections.
* @param diagnosticsCollection the diagnostic collection to start reporting for
*/
void beginReporting();
void beginReporting(String diagnosticsCollection);

/**
* Notification sent after having completed diagnostic process.
* Typically, this would tell a diagnostic collector that no more diagnostics should be expected in this
* iteration.
* collection.
* @param diagnosticsCollection the diagnostic collection to end reporting for
*/
void endReporting();
void endReporting(String diagnosticsCollection);
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

import com.google.inject.assistedinject.Assisted;
import com.google.inject.assistedinject.AssistedInject;

import org.eclipse.che.ide.api.editor.annotation.AnnotationModelImpl;
import org.eclipse.che.ide.api.editor.document.Document;
import org.eclipse.che.ide.api.editor.document.DocumentHandle;
Expand All @@ -21,11 +20,13 @@
import org.eclipse.che.ide.api.editor.text.TextPosition;
import org.eclipse.che.ide.api.editor.texteditor.EditorResources;
import org.eclipse.che.ide.editor.orion.client.OrionAnnotationSeverityProvider;
import org.eclipse.che.ide.util.loging.Log;
import org.eclipse.che.plugin.languageserver.ide.LanguageServerResources;
import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.Range;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -34,10 +35,11 @@
* @author Evgen Vidolob
*/
public class LanguageServerAnnotationModel extends AnnotationModelImpl implements DiagnosticCollector, OrionAnnotationSeverityProvider {
private final LanguageServerResources.LSCss lsCss;
private final EditorResources.EditorCss editorCss;
private List<Diagnostic> diagnostics;
private List<DiagnosticAnnotation> generatedAnnotations = new ArrayList<>();
private final LanguageServerResources.LSCss lsCss;
private final EditorResources.EditorCss editorCss;
private final Map<String, List<Diagnostic>> diagnostics = new HashMap<>();
private final Map<String, List<Diagnostic>> collectedDiagnostics = new HashMap<>();
private final Map<Diagnostic, DiagnosticAnnotation> generatedAnnotations = new HashMap<>();

@AssistedInject
public LanguageServerAnnotationModel(@Assisted final DocumentPositionMap docPositionMap,
Expand Down Expand Up @@ -75,49 +77,66 @@ protected Position createPositionFromDiagnostic(final Diagnostic diagnostic) {
}

@Override
public void acceptDiagnostic(final Diagnostic problem) {
diagnostics.add(problem);
public void acceptDiagnostic(String diagnosticCollection, final Diagnostic problem) {
collectedDiagnostics.get(diagnosticCollection).add(problem);
}

@Override
public void beginReporting() {
diagnostics = new ArrayList<>();
public void beginReporting(String diagnosticCollection) {
collectedDiagnostics.put(diagnosticCollection, new ArrayList<>());
}

@Override
public void endReporting() {
reportDiagnostic();
public void endReporting(String diagnosticCollection) {
reportDiagnostic(diagnosticCollection, collectedDiagnostics.remove(diagnosticCollection));
}

private void reportDiagnostic() {
private void reportDiagnostic(String diagnosticCollection, List<Diagnostic> newDiagnostics) {
boolean temporaryProblemsChanged = false;

if (!generatedAnnotations.isEmpty()) {
temporaryProblemsChanged = true;
super.clear();
generatedAnnotations.clear();
}

if (diagnostics != null && !diagnostics.isEmpty()) {

for (final Diagnostic diagnostic : diagnostics) {
final Position position = createPositionFromDiagnostic(diagnostic);

if (position != null) {
final DiagnosticAnnotation annotation = new DiagnosticAnnotation(diagnostic);
addAnnotation(annotation, position, false);
generatedAnnotations.add(annotation);

temporaryProblemsChanged = true;
}
List<Diagnostic> currentDiagnostics = diagnostics.getOrDefault(diagnosticCollection, Collections.emptyList());
// new list becomes previous list, but make a copy; the collection is modified below.
diagnostics.put(diagnosticCollection, new ArrayList<>(newDiagnostics));

for (Diagnostic diagnostic : currentDiagnostics) {
// go through the current set and remove those that are not present
// in the new set.
if (!newDiagnostics.contains(diagnostic)) {
removeAnnotationFor(diagnostic);
temporaryProblemsChanged= true;
} else {
newDiagnostics.remove(diagnostic);
}
}

for (Diagnostic diagnostic : newDiagnostics) {
// now go through the ones left in the new set: they are new
addAnnotationFor(diagnostic);
temporaryProblemsChanged= true;
}

if (temporaryProblemsChanged) {
fireModelChanged();
}
}

private void addAnnotationFor(Diagnostic diagnostic) {
Log.debug(getClass(), "adding annotation for "+diagnostic);
DiagnosticAnnotation annotation = new DiagnosticAnnotation(diagnostic);
generatedAnnotations.put(diagnostic, annotation);
Position position = createPositionFromDiagnostic(diagnostic);
if (position != null) {
addAnnotation(annotation, position, false);
} else {
Log.error(getClass(), "Position is null for "+diagnostic);
}
}

private void removeAnnotationFor(Diagnostic diagnostic) {
Log.debug(getClass(), "removing annotation for "+diagnostic);
DiagnosticAnnotation annotation = generatedAnnotations.remove(diagnostic);
removeAnnotation(annotation, false);
}

@Override
public Map<String, String> getAnnotationDecorations() {
final Map<String, String> decorations = new HashMap<>();
Expand Down
Loading