Skip to content

Commit

Permalink
eclipse-jdtlsGH-715: Implemented the semantic highlighting support.
Browse files Browse the repository at this point in the history
Closes eclipse-jdtls#715.

Signed-off-by: Akos Kitta <kittaakos@typefox.io>
  • Loading branch information
Akos Kitta committed Oct 12, 2018
1 parent 746e337 commit 948f1cf
Show file tree
Hide file tree
Showing 17 changed files with 3,706 additions and 18 deletions.
3 changes: 2 additions & 1 deletion org.eclipse.jdt.ls.core/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ Export-Package: org.eclipse.jdt.ls.core.internal;x-friends:="org.eclipse.jdt.ls.
org.eclipse.jdt.ls.core.internal.javadoc;x-friends:="org.eclipse.jdt.ls.tests",
org.eclipse.jdt.ls.core.internal.lsp;x-friends:="org.eclipse.jdt.ls.tests",
org.eclipse.jdt.ls.core.internal.managers;x-friends:="org.eclipse.jdt.ls.tests",
org.eclipse.jdt.ls.core.internal.preferences;x-friends:="org.eclipse.jdt.ls.tests"
org.eclipse.jdt.ls.core.internal.preferences;x-friends:="org.eclipse.jdt.ls.tests",
org.eclipse.jdt.ls.core.internal.highlighting;x-friends:="org.eclipse.jdt.ls.tests"
Bundle-ClassPath: lib/jsoup-1.9.2.jar,
lib/remark-1.0.0.jar,
.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.eclipse.lsp4j.MessageType;
import org.eclipse.lsp4j.PublishDiagnosticsParams;
import org.eclipse.lsp4j.RegistrationParams;
import org.eclipse.lsp4j.SemanticHighlightingParams;
import org.eclipse.lsp4j.ShowMessageRequestParams;
import org.eclipse.lsp4j.UnregistrationParams;
import org.eclipse.lsp4j.WorkspaceEdit;
Expand Down Expand Up @@ -195,6 +196,13 @@ public void registerCapability(RegistrationParams params) {
client.registerCapability(params);
}

/**
* @see {@link LanguageClient#semanticHighlighting(SemanticHighlightingParams)}
*/
public void semanticHighlighting(SemanticHighlightingParams params) {
client.semanticHighlighting(params);
}

public void disconnect() {
if (logHandler != null) {
logHandler.uninstall();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
*******************************************************************************/
package org.eclipse.jdt.ls.core.internal.handlers;

import static com.google.common.collect.Lists.newArrayList;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
Expand Down Expand Up @@ -46,12 +48,18 @@
import org.eclipse.jdt.ls.core.internal.JDTUtils;
import org.eclipse.jdt.ls.core.internal.JavaClientConnection;
import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin;
import org.eclipse.jdt.ls.core.internal.highlighting.HighlightedPosition;
import org.eclipse.jdt.ls.core.internal.highlighting.SemanticHighlightingService;
import org.eclipse.jdt.ls.core.internal.highlighting.SemanticHighlightingService.HighlightedPositionDiffContext;
import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager;
import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager.CHANGE_TYPE;
import org.eclipse.jdt.ls.core.internal.preferences.PreferenceManager;
import org.eclipse.jdt.ls.core.internal.preferences.Preferences;
import org.eclipse.jdt.ls.core.internal.preferences.Preferences.Severity;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.BadPositionCategoryException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.lsp4j.Command;
import org.eclipse.lsp4j.DidChangeTextDocumentParams;
Expand All @@ -60,12 +68,15 @@
import org.eclipse.lsp4j.DidSaveTextDocumentParams;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.TextDocumentContentChangeEvent;
import org.eclipse.lsp4j.VersionedTextDocumentIdentifier;
import org.eclipse.text.edits.DeleteEdit;
import org.eclipse.text.edits.InsertEdit;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.ReplaceEdit;
import org.eclipse.text.edits.TextEdit;

import com.google.common.collect.Iterables;

public class DocumentLifeCycleHandler {

public static final String DOCUMENT_LIFE_CYCLE_JOBS = "DocumentLifeCycleJobs";
Expand All @@ -76,12 +87,14 @@ public class DocumentLifeCycleHandler {
private CoreASTProvider sharedASTProvider;
private WorkspaceJob validationTimer;
private Set<ICompilationUnit> toReconcile = new HashSet<>();
private SemanticHighlightingService semanticHighlightingService;

public DocumentLifeCycleHandler(JavaClientConnection connection, PreferenceManager preferenceManager, ProjectsManager projectsManager, boolean delayValidation) {
this.connection = connection;
this.preferenceManager = preferenceManager;
this.projectsManager = projectsManager;
this.sharedASTProvider = CoreASTProvider.getInstance();
this.semanticHighlightingService = new SemanticHighlightingService(this.connection, this.sharedASTProvider, this.preferenceManager);
if (delayValidation) {
this.validationTimer = new WorkspaceJob("Validate documents") {
@Override
Expand Down Expand Up @@ -282,15 +295,17 @@ public void handleOpen(DidOpenTextDocumentParams params) {
buffer.setContents(newContent);
}
triggerValidation(unit);
installSemanticHighlightings(unit);
// see https://github.com/redhat-developer/vscode-java/issues/274
checkPackageDeclaration(uri, unit);
} catch (JavaModelException e) {
JavaLanguageServerPlugin.logException("Error while opening document", e);
} catch (JavaModelException | BadPositionCategoryException e) {
JavaLanguageServerPlugin.logException("Error while opening document. URI: " + uri, e);
}
}

public void handleChanged(DidChangeTextDocumentParams params) {
ICompilationUnit unit = JDTUtils.resolveCompilationUnit(params.getTextDocument().getUri());
String uri = params.getTextDocument().getUri();
ICompilationUnit unit = JDTUtils.resolveCompilationUnit(uri);

if (unit == null || !unit.isWorkingCopy() || params.getContentChanges().isEmpty() || unit.getResource().isDerived()) {
return;
Expand All @@ -301,6 +316,7 @@ public void handleChanged(DidChangeTextDocumentParams params) {
sharedASTProvider.disposeAST();
}
List<TextDocumentContentChangeEvent> contentChanges = params.getContentChanges();
List<HighlightedPositionDiffContext> diffContexts = newArrayList();
for (TextDocumentContentChangeEvent changeEvent : contentChanges) {

Range range = changeEvent.getRange();
Expand All @@ -325,12 +341,33 @@ public void handleChanged(DidChangeTextDocumentParams params) {
} else {
edit = new ReplaceEdit(startOffset, length, text);
}
IDocument document = JsonRpcHelpers.toDocument(unit.getBuffer());
edit.apply(document, TextEdit.NONE);

// Avoid any computation if the `SemanticHighlightingService#isEnabled` is `false`.
if (semanticHighlightingService.isEnabled()) {
IDocument oldState = new Document(unit.getBuffer().getContents());
IDocument newState = JsonRpcHelpers.toDocument(unit.getBuffer());
//@formatter:off
List<HighlightedPosition> oldPositions = diffContexts.isEmpty()
? semanticHighlightingService.getHighlightedPositions(uri)
: Iterables.getLast(diffContexts).newPositions;
//@formatter:on
edit.apply(newState, TextEdit.NONE);
// This is a must. Make the document immutable.
// Otherwise, any consecutive `newStates` get out-of-sync due to the shared buffer from the compilation unit.
newState = new Document(newState.get());
List<HighlightedPosition> newPositions = semanticHighlightingService.calculateHighlightedPositions(unit, true);
DocumentEvent event = new DocumentEvent(newState, startOffset, length, text);
diffContexts.add(new HighlightedPositionDiffContext(oldState, event, oldPositions, newPositions));
} else {
IDocument document = JsonRpcHelpers.toDocument(unit.getBuffer());
edit.apply(document, TextEdit.NONE);
}

}
triggerValidation(unit);
} catch (JavaModelException | MalformedTreeException | BadLocationException e) {
JavaLanguageServerPlugin.logException("Error while handling document change", e);
updateSemanticHighlightings(params.getTextDocument(), diffContexts);
} catch (JavaModelException | MalformedTreeException | BadLocationException | BadPositionCategoryException e) {
JavaLanguageServerPlugin.logException("Error while handling document change. URI: " + uri, e);
}
}

Expand All @@ -354,8 +391,9 @@ public void handleClosed(DidCloseTextDocumentParams params) {
unit.delete(true, null);
}
}
uninstallSemanticHighlightings(uri);
} catch (CoreException e) {
JavaLanguageServerPlugin.logException("Error while handling document close", e);
JavaLanguageServerPlugin.logException("Error while handling document close. URI: " + uri, e);
}
}

Expand All @@ -374,7 +412,7 @@ public void handleSaved(DidSaveTextDocumentParams params) {
unit.discardWorkingCopy();
unit.becomeWorkingCopy(new NullProgressMonitor());
} catch (JavaModelException e) {
JavaLanguageServerPlugin.logException("Error while handling document save", e);
JavaLanguageServerPlugin.logException("Error while handling document save. URI: " + uri, e);
}
}
}
Expand Down Expand Up @@ -423,4 +461,16 @@ private ICompilationUnit checkPackageDeclaration(String uri, ICompilationUnit un
return unit;
}

protected void installSemanticHighlightings(ICompilationUnit unit) throws JavaModelException, BadPositionCategoryException {
this.semanticHighlightingService.install(unit);
}

protected void uninstallSemanticHighlightings(String uri) {
this.semanticHighlightingService.uninstall(uri);
}

protected void updateSemanticHighlightings(VersionedTextDocumentIdentifier textDocument, List<HighlightedPositionDiffContext> diffContexts) throws BadLocationException, BadPositionCategoryException, JavaModelException {
this.semanticHighlightingService.update(textDocument, diffContexts);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin;
import org.eclipse.jdt.ls.core.internal.ResourceUtils;
import org.eclipse.jdt.ls.core.internal.ServiceStatus;
import org.eclipse.jdt.ls.core.internal.highlighting.SemanticHighlightingService;
import org.eclipse.jdt.ls.core.internal.managers.ProjectsManager;
import org.eclipse.jdt.ls.core.internal.preferences.PreferenceManager;
import org.eclipse.jdt.ls.core.internal.preferences.Preferences;
Expand All @@ -46,6 +47,7 @@
import org.eclipse.lsp4j.InitializeParams;
import org.eclipse.lsp4j.InitializeResult;
import org.eclipse.lsp4j.SaveOptions;
import org.eclipse.lsp4j.SemanticHighlightingServerCapabilities;
import org.eclipse.lsp4j.ServerCapabilities;
import org.eclipse.lsp4j.TextDocumentSyncKind;
import org.eclipse.lsp4j.TextDocumentSyncOptions;
Expand Down Expand Up @@ -198,6 +200,12 @@ InitializeResult initialize(InitializeParams param) {
}
capabilities.setTextDocumentSync(textDocumentSyncOptions);

if (preferenceManager.getClientPreferences().isSemanticHighlightingSupported()) {
SemanticHighlightingServerCapabilities semanticHighlightingCapabilities = new SemanticHighlightingServerCapabilities();
semanticHighlightingCapabilities.setScopes(SemanticHighlightingService.getAllScopes());
capabilities.setSemanticHighlighting(semanticHighlightingCapabilities);
}

WorkspaceServerCapabilities wsCapabilities = new WorkspaceServerCapabilities();
WorkspaceFoldersOptions wsFoldersOptions = new WorkspaceFoldersOptions();
wsFoldersOptions.setSupported(Boolean.TRUE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,23 @@ private JsonRpcHelpers(){
* @return
*/
public static int toOffset(IBuffer buffer, int line, int column){
if (buffer != null) {
return toOffset(toDocument(buffer), line, column);
}
return -1;
}

/**
* Convert line, column to a document offset.
*
* @param document
* @param line
* @param column
* @return
*/
public static int toOffset(IDocument document, int line, int column) {
try {
if (buffer != null) {
return toDocument(buffer).getLineOffset(line) + column;
}
return document.getLineOffset(line) + column;
} catch (BadLocationException e) {
JavaLanguageServerPlugin.logException(e.getMessage(), e);
}
Expand All @@ -55,11 +68,21 @@ public static int toOffset(IBuffer buffer, int line, int column){
* @return
*/
public static int[] toLine(IBuffer buffer, int offset){
IDocument document = toDocument(buffer);
return toLine(toDocument(buffer), offset);
}

/**
* Convert the document offset to line number and column.
*
* @param document
* @param line
* @return
*/
public static int[] toLine(IDocument document, int offset) {
try {
int line = document.getLineOfOffset(offset);
int column = offset - document.getLineOffset(line);
return new int[] {line, column};
return new int[] { line, column };
} catch (BadLocationException e) {
JavaLanguageServerPlugin.logException(e.getMessage(), e);
}
Expand Down
Loading

0 comments on commit 948f1cf

Please sign in to comment.