Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorangelozerr2018-07-30 14:42:33 +0000
committerMickael Istria2018-08-02 10:32:08 +0000
commit1bd95e2e2219228bc87dbff40b1cc0bebf91700a (patch)
tree785fe97c3e95d8c7647ef4573d96d256d64693f5
parent19a965840032cae962561902ca70c1b215b98d8d (diff)
downloadlsp4e-1bd95e2e2219228bc87dbff40b1cc0bebf91700a.tar.gz
lsp4e-1bd95e2e2219228bc87dbff40b1cc0bebf91700a.tar.xz
lsp4e-1bd95e2e2219228bc87dbff40b1cc0bebf91700a.zip
Bug 533322 - [code mining] Support ‘textDocument/documentColor’ with
CodeMining Change-Id: Icaa99403c00940f215949194440e08d1edd4f19e Signed-off-by: angelozerr <angelo.zerr@gmail.com>
-rw-r--r--org.eclipse.lsp4e/plugin.xml13
-rw-r--r--org.eclipse.lsp4e/src/org/eclipse/lsp4e/LSPEclipseUtils.java30
-rw-r--r--org.eclipse.lsp4e/src/org/eclipse/lsp4e/LanguageServerWrapper.java2
-rw-r--r--org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/color/ColorInformationMining.java168
-rw-r--r--org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/color/DocumentColorProvider.java118
5 files changed, 331 insertions, 0 deletions
diff --git a/org.eclipse.lsp4e/plugin.xml b/org.eclipse.lsp4e/plugin.xml
index 646e1243..c8e366f6 100644
--- a/org.eclipse.lsp4e/plugin.xml
+++ b/org.eclipse.lsp4e/plugin.xml
@@ -426,6 +426,19 @@
</with>
</enabledWhen>
</codeMiningProvider>
+ <codeMiningProvider
+ class="org.eclipse.lsp4e.operations.color.DocumentColorProvider"
+ id="org.eclipse.lsp4e.documentColor"
+ label="Color">
+ <enabledWhen>
+ <with
+ variable="editorInput">
+ <test
+ property="org.eclipse.lsp4e.hasLanguageServer">
+ </test>
+ </with>
+ </enabledWhen>
+ </codeMiningProvider>
</extension>
<extension
point="org.eclipse.ui.genericeditor.reconcilers">
diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/LSPEclipseUtils.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/LSPEclipseUtils.java
index 9d3e6003..fb2f5728 100644
--- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/LSPEclipseUtils.java
+++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/LSPEclipseUtils.java
@@ -55,6 +55,7 @@ import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.RewriteSessionEditProcessor;
import org.eclipse.jface.text.TextSelection;
+import org.eclipse.lsp4j.Color;
import org.eclipse.lsp4j.CompletionParams;
import org.eclipse.lsp4j.DiagnosticSeverity;
import org.eclipse.lsp4j.Location;
@@ -73,6 +74,8 @@ import org.eclipse.lsp4j.jsonrpc.validation.NonNull;
import org.eclipse.ltk.core.refactoring.CompositeChange;
import org.eclipse.ltk.core.refactoring.DocumentChange;
import org.eclipse.ltk.core.refactoring.PerformChangeOperation;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.graphics.RGBA;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.MultiTextEdit;
import org.eclipse.text.edits.ReplaceEdit;
@@ -610,4 +613,31 @@ public class LSPEclipseUtils {
}
return null;
}
+
+ /**
+ * Convert the given Eclipse <code>rgb</code> instance to a LSP {@link Color}
+ * instance.
+ *
+ * @param rgb
+ * the rgb instance to convert
+ * @return the given Eclipse <code>rgb</code> instance to a LSP {@link Color}
+ * instance.
+ */
+ public static Color toColor(RGB rgb) {
+ return new Color(rgb.red / 255d, rgb.green / 255d, rgb.blue / 255d, 1);
+ }
+
+ /**
+ * Convert the given LSP <code>color</code> instance to a Eclipse {@link RGBA}
+ * instance.
+ *
+ * @param rgb
+ * the color instance to convert
+ * @return the given LSP <code>color</code> instance to a Eclipse {@link RGBA}
+ * instance.
+ */
+ public static RGBA toRGBA(Color color) {
+ return new RGBA((int) (color.getRed() * 255), (int) (color.getGreen() * 255), (int) (color.getBlue() * 255),
+ (int) color.getAlpha());
+ }
}
diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/LanguageServerWrapper.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/LanguageServerWrapper.java
index fbaaaf57..02ca6919 100644
--- a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/LanguageServerWrapper.java
+++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/LanguageServerWrapper.java
@@ -61,6 +61,7 @@ import org.eclipse.lsp4j.ClientCapabilities;
import org.eclipse.lsp4j.CodeActionCapabilities;
import org.eclipse.lsp4j.CodeActionLiteralSupportCapabilities;
import org.eclipse.lsp4j.CodeLensCapabilities;
+import org.eclipse.lsp4j.ColorProviderCapabilities;
import org.eclipse.lsp4j.CompletionCapabilities;
import org.eclipse.lsp4j.CompletionItemCapabilities;
import org.eclipse.lsp4j.DefinitionCapabilities;
@@ -235,6 +236,7 @@ public class LanguageServerWrapper {
codeActionCapabilities.setCodeActionLiteralSupport(new CodeActionLiteralSupportCapabilities());
textDocumentClientCapabilities.setCodeAction(codeActionCapabilities);
textDocumentClientCapabilities.setCodeLens(new CodeLensCapabilities());
+ textDocumentClientCapabilities.setColorProvider(new ColorProviderCapabilities());
textDocumentClientCapabilities.setCompletion(new CompletionCapabilities(new CompletionItemCapabilities(Boolean.TRUE)));
textDocumentClientCapabilities.setDefinition(new DefinitionCapabilities());
textDocumentClientCapabilities.setDocumentHighlight(new DocumentHighlightCapabilities());
diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/color/ColorInformationMining.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/color/ColorInformationMining.java
new file mode 100644
index 00000000..22531381
--- /dev/null
+++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/color/ColorInformationMining.java
@@ -0,0 +1,168 @@
+/**
+ * Copyright (c) 2018 Angelo ZERR.
+ * 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
+ *
+ * Contributors:
+ * Angelo Zerr <angelo.zerr@gmail.com> - [code mining] Support 'textDocument/documentColor' with CodeMining - Bug 533322
+ */
+package org.eclipse.lsp4e.operations.color;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.Position;
+import org.eclipse.jface.text.codemining.LineContentCodeMining;
+import org.eclipse.jface.util.Geometry;
+import org.eclipse.lsp4e.LSPEclipseUtils;
+import org.eclipse.lsp4e.LanguageServerPlugin;
+import org.eclipse.lsp4j.ColorInformation;
+import org.eclipse.lsp4j.ColorPresentationParams;
+import org.eclipse.lsp4j.Range;
+import org.eclipse.lsp4j.TextDocumentIdentifier;
+import org.eclipse.lsp4j.TextEdit;
+import org.eclipse.lsp4j.services.LanguageServer;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.FontMetrics;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.graphics.RGB;
+import org.eclipse.swt.graphics.RGBA;
+import org.eclipse.swt.graphics.Rectangle;
+import org.eclipse.swt.widgets.ColorDialog;
+import org.eclipse.swt.widgets.Shell;
+
+/**
+ * Draw the LSP color information with a colorized square.
+ *
+ */
+public class ColorInformationMining extends LineContentCodeMining {
+
+ private final RGBA rgba;
+ private final DocumentColorProvider colorProvider;
+
+ /**
+ * Click on colorized square opens a color dialog to pick a color and update
+ * text color declaration.
+ *
+ */
+ private static class UpdateColorWithDialog implements Consumer<MouseEvent> {
+
+ private final TextDocumentIdentifier textDocumentIdentifier;
+ private final ColorInformation colorInformation;
+ private final CompletableFuture<LanguageServer> languageServer;
+ private final IDocument document;
+
+ public UpdateColorWithDialog(TextDocumentIdentifier textDocumentIdentifier, ColorInformation colorInformation,
+ CompletableFuture<LanguageServer> languageServer, IDocument document) {
+ this.textDocumentIdentifier = textDocumentIdentifier;
+ this.colorInformation = colorInformation;
+ this.languageServer = languageServer;
+ this.document = document;
+ }
+
+ @Override
+ public void accept(MouseEvent event) {
+ StyledText styledText = (StyledText) event.widget;
+ Shell shell = new Shell(styledText.getDisplay());
+ Rectangle location = Geometry.toDisplay(styledText, new Rectangle(event.x, event.y, 1, 1));
+ shell.setLocation(location.x, location.y);
+ // Open color dialog
+ ColorDialog dialog = new ColorDialog(shell);
+ dialog.setRGB(LSPEclipseUtils.toRGBA(colorInformation.getColor()).rgb);
+ RGB rgb = dialog.open();
+ if (rgb != null) {
+ // get LSP color presentation list for the picked color
+ ColorPresentationParams params = new ColorPresentationParams(textDocumentIdentifier,
+ LSPEclipseUtils.toColor(rgb), colorInformation.getRange());
+ this.languageServer.thenCompose(
+ ls -> ls.getTextDocumentService().colorPresentation(params).thenAccept(presentations -> {
+ if (presentations.isEmpty()) {
+ return;
+ }
+ // As ColorDialog cannot be customized (to choose the color presentation (rgb,
+ // hexa, ....) we pick the first color presentation.
+ try {
+ TextEdit textEdit = presentations.get(0).getTextEdit();
+ LSPEclipseUtils.applyEdit(textEdit, document);
+ } catch (BadLocationException e) {
+ LanguageServerPlugin.logError(e);
+ }
+ }));
+ }
+ }
+
+ }
+
+ public ColorInformationMining(ColorInformation colorInformation, @NonNull IDocument document,
+ TextDocumentIdentifier textDocumentIdentifier, CompletableFuture<LanguageServer> languageServer,
+ DocumentColorProvider colorProvider) throws BadLocationException {
+ super(toPosition(colorInformation.getRange(), document), colorProvider,
+ new UpdateColorWithDialog(textDocumentIdentifier, colorInformation, languageServer, document));
+ this.rgba = LSPEclipseUtils.toRGBA(colorInformation.getColor());
+ this.colorProvider = colorProvider;
+ // set label with space to mark the mining as resolved.
+ super.setLabel(" "); //$NON-NLS-1$
+ }
+
+ @Override
+ public Point draw(GC gc, StyledText textWidget, Color color, int x, int y) {
+ FontMetrics fontMetrics = gc.getFontMetrics();
+ // Compute position and size of the color square
+ int size = getSquareSize(fontMetrics);
+ x += fontMetrics.getLeading();
+ y += fontMetrics.getDescent();
+ Rectangle rect = new Rectangle(x, y, size, size);
+ // Fill square
+ gc.setBackground(colorProvider.getColor(this.rgba, textWidget.getDisplay()));
+ gc.fillRectangle(rect);
+ // Draw square box
+ gc.setForeground(textWidget.getForeground());
+ gc.drawRectangle(rect);
+ return new Point(getSquareWidth(fontMetrics), size);
+ }
+
+ /**
+ * Returns the colorized square size.
+ *
+ * @param fontMetrics
+ * @return the colorized square size.
+ */
+ private static int getSquareSize(FontMetrics fontMetrics) {
+ return fontMetrics.getHeight() - 2 * fontMetrics.getDescent();
+ }
+
+ /**
+ * Compute width of square
+ *
+ * @param styledText
+ * @return the width of square
+ */
+ private static int getSquareWidth(FontMetrics fontMetrics) {
+ // width = 1 space + size width of square
+ int width = (int) fontMetrics.getAverageCharacterWidth() + getSquareSize(fontMetrics);
+ return width;
+ }
+
+ /**
+ * Returns the Eclipse position from the given LSP range.
+ *
+ * @param range
+ * the LSP range to convert
+ * @param document
+ * @return the Eclipse position from the given LSP range.
+ * @throws BadLocationException
+ */
+ private static Position toPosition(Range range, IDocument document) throws BadLocationException {
+ int start = LSPEclipseUtils.toOffset(range.getStart(), document);
+ int end = LSPEclipseUtils.toOffset(range.getEnd(), document);
+ return new Position(start, end - start);
+ }
+}
diff --git a/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/color/DocumentColorProvider.java b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/color/DocumentColorProvider.java
new file mode 100644
index 00000000..f4a2ded8
--- /dev/null
+++ b/org.eclipse.lsp4e/src/org/eclipse/lsp4e/operations/color/DocumentColorProvider.java
@@ -0,0 +1,118 @@
+/**
+ * Copyright (c) 2018 Angelo ZERR.
+ * 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
+ *
+ * Contributors:
+ * Angelo Zerr <angelo.zerr@gmail.com> - [code mining] Support 'textDocument/documentColor' with CodeMining - Bug 533322
+ */
+package org.eclipse.lsp4e.operations.color;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.text.codemining.AbstractCodeMiningProvider;
+import org.eclipse.jface.text.codemining.ICodeMining;
+import org.eclipse.lsp4e.LanguageServerPlugin;
+import org.eclipse.lsp4e.LanguageServiceAccessor;
+import org.eclipse.lsp4e.LanguageServiceAccessor.LSPDocumentInfo;
+import org.eclipse.lsp4j.ColorInformation;
+import org.eclipse.lsp4j.DocumentColorParams;
+import org.eclipse.lsp4j.ServerCapabilities;
+import org.eclipse.lsp4j.TextDocumentIdentifier;
+import org.eclipse.swt.graphics.Color;
+import org.eclipse.swt.graphics.RGBA;
+import org.eclipse.swt.widgets.Display;
+
+/**
+ * Consume the 'textDocument/documentColor' request to decorate color references
+ * in the editor.
+ *
+ */
+public class DocumentColorProvider extends AbstractCodeMiningProvider {
+
+ private final Map<RGBA, Color> colorTable;
+
+ public DocumentColorProvider() {
+ colorTable = new HashMap<>();
+ }
+
+ private CompletableFuture<List<? extends ICodeMining>> provideCodeMinings(@NonNull IDocument document) {
+ return CompletableFuture.supplyAsync(() -> {
+ List<@NonNull LSPDocumentInfo> docInfos = LanguageServiceAccessor.getLSPDocumentInfosFor(document,
+ (capabilities) -> (capabilities.getColorProvider() != null
+ && ((capabilities.getColorProvider().getLeft() != null
+ && capabilities.getColorProvider().getLeft())
+ || capabilities.getColorProvider().getRight() != null)));
+ final CompletableFuture<?>[] requests = new CompletableFuture<?>[docInfos.size()];
+ final List<ColorInformationMining> colorResults = Collections
+ .synchronizedList(new ArrayList<>(docInfos.size()));
+ for (int i = 0; i < docInfos.size(); i++) {
+ final LSPDocumentInfo info = docInfos.get(i);
+ final ServerCapabilities capabilites = info.getCapabilites();
+ final TextDocumentIdentifier textDocumentIdentifier = new TextDocumentIdentifier(
+ info.getFileUri().toString());
+ DocumentColorParams param = new DocumentColorParams(textDocumentIdentifier);
+ requests[i] = info.getInitializedLanguageClient()
+ .thenCompose(languageServer -> languageServer.getTextDocumentService().documentColor(param))
+ .thenAccept(colors -> {
+ for (ColorInformation color : colors) {
+ if (color != null && capabilites != null) {
+ try {
+ colorResults.add(new ColorInformationMining(color, document,
+ textDocumentIdentifier, info.getInitializedLanguageClient(),
+ DocumentColorProvider.this));
+ } catch (BadLocationException e) {
+ LanguageServerPlugin.logError(e);
+ }
+ }
+ }
+ });
+ }
+ CompletableFuture.allOf(requests).join();
+ return colorResults;
+ });
+ }
+
+ @Override
+ public CompletableFuture<List<? extends ICodeMining>> provideCodeMinings(ITextViewer viewer,
+ IProgressMonitor monitor) {
+ return provideCodeMinings(viewer.getDocument());
+ }
+
+ /**
+ * Returns the color from the given rgba.
+ *
+ * @param rgba
+ * the rgba declaration
+ * @param display
+ * the display to use to create a color instance
+ * @return the color from the given rgba.
+ */
+ public Color getColor(RGBA rgba, Display display) {
+ Color color = colorTable.get(rgba);
+ if (color == null) {
+ color = new Color(display, rgba);
+ colorTable.put(rgba, color);
+ }
+ return color;
+ }
+
+ @Override
+ public void dispose() {
+ colorTable.values().forEach(color -> color.dispose());
+ super.dispose();
+ }
+
+}

Back to the top