Skip to content

Commit

Permalink
CodeLens, References, Rename, Diagnostics support for XML references
Browse files Browse the repository at this point in the history
Signed-off-by: azerr <azerr@redhat.com>
  • Loading branch information
angelozerr committed Jan 12, 2023
1 parent 1663001 commit 7a9c3de
Show file tree
Hide file tree
Showing 55 changed files with 4,064 additions and 876 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,10 @@
import org.eclipse.lsp4j.LinkedEditingRanges;
import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.LocationLink;
import org.eclipse.lsp4j.PrepareRenameParams;
import org.eclipse.lsp4j.PrepareRenameResult;
import org.eclipse.lsp4j.PublishDiagnosticsParams;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.ReferenceParams;
import org.eclipse.lsp4j.RenameParams;
import org.eclipse.lsp4j.SelectionRange;
Expand Down Expand Up @@ -349,10 +352,18 @@ public CompletableFuture<List<? extends TextEdit>> rangeFormatting(DocumentRange
});
}

@Override
public CompletableFuture<Either<Range, PrepareRenameResult>> prepareRename(PrepareRenameParams params) {
return computeDOMAsync(params.getTextDocument(), (xmlDocument, cancelChecker) -> {
return getXMLLanguageService().prepareRename(xmlDocument, params.getPosition(), cancelChecker);
});
}

@Override
public CompletableFuture<WorkspaceEdit> rename(RenameParams params) {
return computeDOMAsync(params.getTextDocument(), (xmlDocument, cancelChecker) -> {
return getXMLLanguageService().doRename(xmlDocument, params.getPosition(), params.getNewName());
return getXMLLanguageService().doRename(xmlDocument, params.getPosition(), params.getNewName(),
cancelChecker);
});
}

Expand Down Expand Up @@ -563,14 +574,14 @@ public CompletableFuture<List<ColorInformation>> documentColor(DocumentColorPara
return getXMLLanguageService().findDocumentColors(xmlDocument, cancelChecker);
});
}

@Override
public CompletableFuture<List<ColorPresentation>> colorPresentation(ColorPresentationParams params) {
return computeDOMAsync(params.getTextDocument(), (xmlDocument, cancelChecker) -> {
return getXMLLanguageService().getColorPresentations(xmlDocument, params, cancelChecker);
});
}

@Override
public void didSave(DidSaveTextDocumentParams params) {
computeAsync((monitor) -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -631,15 +631,6 @@ public DOMText findTextAt(int offset) {
text.parent = this;
return text;
}
DOMNode node = super.findNodeAt(offset);
if (node != null) {
if (node.isText()) {
return (DOMText) node;
}
if (node.isElement() && node != this) {
return ((DOMElement) node).findTextAt(offset);
}
}
return null;
return findTextAt(this, offset);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,17 @@ public static DOMAttr findAttrAt(DOMNode node, int offset) {
return null;
}

public static DOMText findTextAt(DOMNode node, int offset) {
if (node != null && node.hasChildNodes()) {
for (DOMNode child : node.getChildren()) {
if (child.isText() && isIncluded(child, offset)) {
return (DOMText) child;
}
}
}
return null;
}

public static DOMNode findNodeOrAttrAt(DOMDocument document, int offset) {
DOMNode node = document.findNodeAt(offset);
if (node != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,25 @@
*******************************************************************************/
package org.eclipse.lemminx.extensions.references;

import org.eclipse.lemminx.extensions.references.participants.XMLReferencesCodeLensParticipant;
import org.eclipse.lemminx.extensions.references.participants.XMLReferencesCompletionParticipant;
import org.eclipse.lemminx.extensions.references.participants.XMLReferencesDefinitionParticipant;
import org.eclipse.lemminx.extensions.references.participants.XMLReferencesDiagnosticParticipant;
import org.eclipse.lemminx.extensions.references.participants.XMLReferencesHighlightingParticipant;
import org.eclipse.lemminx.extensions.references.participants.XMLReferencesLinkedEditingRangesParticipant;
import org.eclipse.lemminx.extensions.references.participants.XMLReferencesReferenceParticipant;
import org.eclipse.lemminx.extensions.references.participants.XMLReferencesRenameParticipant;
import org.eclipse.lemminx.extensions.references.settings.XMLReferencesSettings;
import org.eclipse.lemminx.services.extensions.IDefinitionParticipant;
import org.eclipse.lemminx.services.extensions.IHighlightingParticipant;
import org.eclipse.lemminx.services.extensions.ILinkedEditingRangesParticipant;
import org.eclipse.lemminx.services.extensions.IReferenceParticipant;
import org.eclipse.lemminx.services.extensions.IRenameParticipant;
import org.eclipse.lemminx.services.extensions.IXMLExtension;
import org.eclipse.lemminx.services.extensions.XMLExtensionsRegistry;
import org.eclipse.lemminx.services.extensions.codelens.ICodeLensParticipant;
import org.eclipse.lemminx.services.extensions.completion.ICompletionParticipant;
import org.eclipse.lemminx.services.extensions.diagnostics.IDiagnosticsParticipant;
import org.eclipse.lemminx.services.extensions.save.ISaveContext;
import org.eclipse.lsp4j.InitializeParams;

Expand Down Expand Up @@ -66,14 +76,24 @@ public class XMLReferencesPlugin implements IXMLExtension {

private final ICompletionParticipant completionParticipant;
private final IDefinitionParticipant definitionParticipant;
private final IReferenceParticipant referenceParticipant;
private final ICodeLensParticipant codeLensParticipant;
private final IHighlightingParticipant highlightingParticipant;
private final IRenameParticipant renameParticipant;
private final ILinkedEditingRangesParticipant linkedEditingRangesParticipant;
private final IDiagnosticsParticipant diagnosticsParticipant;

private XMLReferencesSettings referencesSettings;

public XMLReferencesPlugin() {
completionParticipant = new XMLReferencesCompletionParticipant(this);
definitionParticipant = new XMLReferencesDefinitionParticipant(this);
referenceParticipant = new XMLReferencesReferenceParticipant(this);
codeLensParticipant = new XMLReferencesCodeLensParticipant(this);
highlightingParticipant = new XMLReferencesHighlightingParticipant(this);
renameParticipant = new XMLReferencesRenameParticipant(this);
linkedEditingRangesParticipant = new XMLReferencesLinkedEditingRangesParticipant(this);
diagnosticsParticipant = new XMLReferencesDiagnosticParticipant(this);
}

@Override
Expand All @@ -99,14 +119,24 @@ private void updateSettings(XMLReferencesSettings settings, ISaveContext context
public void start(InitializeParams params, XMLExtensionsRegistry registry) {
registry.registerCompletionParticipant(completionParticipant);
registry.registerDefinitionParticipant(definitionParticipant);
registry.registerReferenceParticipant(referenceParticipant);
registry.registerCodeLensParticipant(codeLensParticipant);
registry.registerHighlightingParticipant(highlightingParticipant);
registry.registerRenameParticipant(renameParticipant);
registry.registerLinkedEditingRangesParticipants(linkedEditingRangesParticipant);
registry.registerDiagnosticsParticipant(diagnosticsParticipant);
}

@Override
public void stop(XMLExtensionsRegistry registry) {
registry.unregisterCompletionParticipant(completionParticipant);
registry.unregisterDefinitionParticipant(definitionParticipant);
registry.unregisterReferenceParticipant(referenceParticipant);
registry.unregisterCodeLensParticipant(codeLensParticipant);
registry.unregisterHighlightingParticipant(highlightingParticipant);
registry.unregisterRenameParticipant(renameParticipant);
registry.unregisterLinkedEditingRangesParticipants(linkedEditingRangesParticipant);
registry.unregisterDiagnosticsParticipant(diagnosticsParticipant);
}

public XMLReferencesSettings getReferencesSettings() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*******************************************************************************
* Copyright (c) 2023 Red Hat Inc. and others.
* All rights reserved. This program and the accompanying materials
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.lemminx.extensions.references.participants;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.lemminx.client.CodeLensKind;
import org.eclipse.lemminx.dom.DOMAttr;
import org.eclipse.lemminx.dom.DOMDocument;
import org.eclipse.lemminx.dom.DOMElement;
import org.eclipse.lemminx.dom.DOMNode;
import org.eclipse.lemminx.extensions.references.XMLReferencesPlugin;
import org.eclipse.lemminx.extensions.references.search.ReferenceLink;
import org.eclipse.lemminx.extensions.references.search.SearchEngine;
import org.eclipse.lemminx.extensions.references.search.SearchNode;
import org.eclipse.lemminx.services.extensions.codelens.ICodeLensParticipant;
import org.eclipse.lemminx.services.extensions.codelens.ICodeLensRequest;
import org.eclipse.lemminx.services.extensions.codelens.ReferenceCommand;
import org.eclipse.lemminx.utils.XMLPositionUtility;
import org.eclipse.lsp4j.CodeLens;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.jsonrpc.CancelChecker;

/**
* XML references codelens support.
*
*/
public class XMLReferencesCodeLensParticipant implements ICodeLensParticipant {

private final XMLReferencesPlugin plugin;

public XMLReferencesCodeLensParticipant(XMLReferencesPlugin plugin) {
this.plugin = plugin;
}

@Override
public void doCodeLens(ICodeLensRequest request, List<CodeLens> lenses, CancelChecker cancelChecker) {
DOMDocument document = request.getDocument();
Collection<ReferenceLink> links = SearchEngine.getInstance().searchLinks(document, plugin.getReferencesSettings(),
cancelChecker);
if (links.isEmpty()) {
return;
}
boolean supportedByClient = request.isSupportedByClient(CodeLensKind.References);
Map<DOMElement, CodeLens> cache = new HashMap<>();
for (ReferenceLink link : links) {
for (SearchNode to : link.getTos()) {
// Increment references count Codelens for the given target element
DOMNode toNode = to.getNode();
DOMElement toElement = toNode.isAttribute() ? ((DOMAttr) toNode).getOwnerElement()
: toNode.getParentElement();
if (toElement != null) {
for (SearchNode from : link.getFroms()) {
if (from.matchesValue(to)) {

CodeLens codeLens = cache.get(toElement);
if (codeLens == null) {
Range range = XMLPositionUtility.createRange(toNode);
codeLens = new CodeLens(range);
codeLens.setCommand(
new ReferenceCommand(document.getDocumentURI(), range.getStart(),
supportedByClient));
cache.put(toElement, codeLens);
lenses.add(codeLens);
} else {
((ReferenceCommand) codeLens.getCommand()).increment();
}

}
}
}
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@
*******************************************************************************/
package org.eclipse.lemminx.extensions.references.participants;

import org.eclipse.lemminx.dom.DOMElement;
import org.eclipse.lemminx.dom.DOMNode;
import java.util.concurrent.atomic.AtomicReference;

import org.eclipse.lemminx.extensions.references.XMLReferencesPlugin;
import org.eclipse.lemminx.extensions.references.settings.XMLReferenceExpression;
import org.eclipse.lemminx.extensions.references.utils.XMLReferencesSearchContext;
import org.eclipse.lemminx.extensions.references.utils.XMLReferencesUtils;
import org.eclipse.lemminx.extensions.references.search.SearchEngine;
import org.eclipse.lemminx.extensions.references.search.SearchQuery;
import org.eclipse.lemminx.extensions.references.search.SearchQueryFactory;
import org.eclipse.lemminx.services.extensions.completion.CompletionParticipantAdapter;
import org.eclipse.lemminx.services.extensions.completion.ICompletionRequest;
import org.eclipse.lemminx.services.extensions.completion.ICompletionResponse;
import org.eclipse.lemminx.utils.XMLPositionUtility;
import org.eclipse.lsp4j.CompletionItem;
import org.eclipse.lsp4j.CompletionItemKind;
import org.eclipse.lsp4j.Range;
Expand All @@ -44,52 +45,47 @@ public XMLReferencesCompletionParticipant(XMLReferencesPlugin plugin) {
@Override
public void onXMLContent(ICompletionRequest request, ICompletionResponse response, CancelChecker cancelChecker)
throws Exception {
DOMNode fromNode = request.getNode();
if (fromNode.isElement()) {
fromNode = ((DOMElement) fromNode).findTextAt(request.getOffset());
}
searchToNodes(fromNode, request, response);
searchToNodes(request, response, cancelChecker);
}

@Override
public void onAttributeValue(String valuePrefix, ICompletionRequest request, ICompletionResponse response,
CancelChecker cancelChecker) throws Exception {
DOMNode node = request.getNode();
DOMNode fromNode = node.findAttrAt(request.getOffset());
searchToNodes(fromNode, request, response);
searchToNodes(request, response, cancelChecker);
}

private void searchToNodes(DOMNode fromNode, ICompletionRequest request, ICompletionResponse response) {
XMLReferencesSearchContext searchContext = XMLReferencesUtils.findExpressionsWhichMatchFrom(fromNode,
private void searchToNodes(ICompletionRequest request, ICompletionResponse response,
CancelChecker cancelChecker) {
// Create the from query for the node which needs to perform the search.
SearchQuery query = SearchQueryFactory.createFromQuery(request.getNode(), request.getOffset(),
plugin.getReferencesSettings());
if (searchContext != null) {
XMLReferencesUtils.searchToNodes(fromNode, searchContext, false, true,
(toNamespacePrefix, toNode, expression) -> {
CompletionItem item = new CompletionItem();
String value = createReferenceValue(toNode, toNamespacePrefix, expression);
String insertText = request.getInsertAttrValue(value);
item.setLabel(value);
item.setKind(CompletionItemKind.Value);
item.setFilterText(insertText);
Range fullRange = request.getReplaceRange();
item.setTextEdit(Either.forLeft(new TextEdit(fullRange, insertText)));
response.addCompletionItem(item);
});
if (query == null) {
// The query cannot be created because:
// - the node is neither a text nor an attribute
// - it doesn't exists some expressions for the DOM document of the node.
// - there are none expressions which matches the node.
return;
}
}
query.setMatchNode(false);
query.setSearchInIncludedFiles(true);

private static String createReferenceValue(DOMNode toNode, String toNamespacePrefix,
XMLReferenceExpression expression) {
StringBuilder value = new StringBuilder();
if (expression.getPrefix() != null) {
value.append(expression.getPrefix());
}
if (toNamespacePrefix != null) {
value.append(toNamespacePrefix);
value.append(":");
}
value.append(XMLReferencesUtils.getNodeValue(toNode));
return value.toString();
AtomicReference<Range> replaceRange = new AtomicReference<>(null);
SearchEngine.getInstance().search(query,
(fromSearchNode, toSearchNode, expression) -> {
CompletionItem item = new CompletionItem();
String value = toSearchNode.getValue(fromSearchNode.getPrefix());
String insertText = request.getInsertAttrValue(value);
item.setLabel(value);
item.setKind(CompletionItemKind.Value);
item.setFilterText(insertText);
Range fullRange = replaceRange.get();
if (fullRange == null) {
replaceRange.set(XMLPositionUtility.createRange(fromSearchNode));
fullRange = replaceRange.get();
}
item.setTextEdit(Either.forLeft(new TextEdit(fullRange, insertText)));
response.addCompletionItem(item);
}, cancelChecker);
}

}
Loading

0 comments on commit 7a9c3de

Please sign in to comment.