blob: 443455e9cafcecabd85afa97596249fbe951ea40 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2018, 2021 Angelo Zerr and others.
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Angelo Zerr <angelo.zerr@gmail.com> - [code mining] Support 'textDocument/documentColor' with CodeMining - Bug 533322
*/
package org.eclipse.lsp4e.operations.color;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
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.LSPEclipseUtils;
import org.eclipse.lsp4e.LanguageServerPlugin;
import org.eclipse.lsp4e.LanguageServiceAccessor;
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) {
URI docURI = LSPEclipseUtils.toUri(document);
if (docURI != null) {
TextDocumentIdentifier textDocumentIdentifier = new TextDocumentIdentifier(docURI.toString());
DocumentColorParams param = new DocumentColorParams(textDocumentIdentifier);
final List<ColorInformationMining> colorResults = Collections.synchronizedList(new ArrayList<>());
return LanguageServiceAccessor.getLanguageServers(document, DocumentColorProvider::isColorProvider)
.thenComposeAsync(languageServers -> CompletableFuture
.allOf(languageServers.stream().map(languageServer -> languageServer
.getTextDocumentService().documentColor(param).thenAcceptAsync(colors -> {
if (colors != null) {
colors.stream().filter(Objects::nonNull).map(color -> {
ColorInformationMining mining = null;
try {
mining = new ColorInformationMining(color, document,
textDocumentIdentifier, languageServer,
DocumentColorProvider.this);
} catch (BadLocationException e) {
LanguageServerPlugin.logError(e);
}
return mining;
}).filter(Objects::nonNull).forEach(colorResults::add);
}
})).toArray(CompletableFuture[]::new)))
.thenApplyAsync(theVoid -> colorResults);
} else {
return null;
}
}
@Override
public CompletableFuture<List<? extends ICodeMining>> provideCodeMinings(ITextViewer viewer,
IProgressMonitor monitor) {
IDocument document = viewer.getDocument();
return document != null ? provideCodeMinings(document) : null;
}
/**
* 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) {
return colorTable.computeIfAbsent(rgba, key -> new Color(display, rgba));
}
private static boolean isColorProvider(ServerCapabilities capabilities) {
return capabilities.getColorProvider() != null
&& ((capabilities.getColorProvider().getLeft() != null && capabilities.getColorProvider().getLeft())
|| capabilities.getColorProvider().getRight() != null);
}
}