Skip to content

Commit

Permalink
Add support for textDocument/definition for XML Schema
Browse files Browse the repository at this point in the history
Fix #148

This PR manage the following definition only in the XML Schema (external
definition is not managed):

 - xs:element/@type -> xs:complexType/@name
 - xs:extension/@base -> xs:complexType/@name

Signed-off-by: azerr <[email protected]>
  • Loading branch information
angelozerr authored and NikolasKomonen committed Jun 20, 2019
1 parent 231bf5d commit 140a8c7
Show file tree
Hide file tree
Showing 13 changed files with 475 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
import org.eclipse.lsp4xml.settings.XMLFormattingOptions;
import org.eclipse.lsp4xml.settings.XMLIncrementalSupportSettings;
import org.eclipse.lsp4xml.settings.XMLSymbolSettings;
import org.eclipse.lsp4xml.utils.XMLPositionUtility;

/**
* XML text document service.
Expand Down Expand Up @@ -128,6 +129,7 @@ public void triggerValidationIfNeeded() {
final ScheduledExecutorService delayer = Executors.newScheduledThreadPool(2);
private boolean codeActionLiteralSupport;
private boolean hierarchicalDocumentSymbolSupport;
private boolean definitionLinkSupport;

public XMLTextDocumentService(XMLLanguageServer xmlLanguageServer) {
this.xmlLanguageServer = xmlLanguageServer;
Expand All @@ -148,6 +150,9 @@ public void updateClientCapabilities(ClientCapabilities capabilities) {
hierarchicalDocumentSymbolSupport = textDocumentClientCapabilities.getDocumentSymbol() != null
&& textDocumentClientCapabilities.getDocumentSymbol().getHierarchicalDocumentSymbolSupport() != null
&& textDocumentClientCapabilities.getDocumentSymbol().getHierarchicalDocumentSymbolSupport();
definitionLinkSupport = textDocumentClientCapabilities.getDefinition() != null
&& textDocumentClientCapabilities.getDefinition().getLinkSupport() != null
&& textDocumentClientCapabilities.getDefinition().getLinkSupport();
}
}

Expand Down Expand Up @@ -279,7 +284,15 @@ public CompletableFuture<List<DocumentLink>> documentLink(DocumentLinkParams par
public CompletableFuture<Either<List<? extends Location>, List<? extends LocationLink>>> definition(
TextDocumentPositionParams params) {
return computeDOMAsync(params.getTextDocument(), (cancelChecker, xmlDocument) -> {
return Either.forLeft(getXMLLanguageService().findDefinition(xmlDocument, params.getPosition()));
if (definitionLinkSupport) {
return Either.forRight(getXMLLanguageService().findDefinition(xmlDocument, params.getPosition(), cancelChecker));
}
List<? extends Location> locations = getXMLLanguageService()
.findDefinition(xmlDocument, params.getPosition(), cancelChecker) //
.stream() //
.map(locationLink -> XMLPositionUtility.toLocation(locationLink)) //
.collect(Collectors.toList());
return Either.forLeft(locations);
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ public class DOMAttr extends DOMNode implements org.w3c.dom.Attr {

private DOMNode nodeAttrValue;

private String quotelessValue;//Value without quotes
private String quotelessValue;// Value without quotes

private String originalValue;//Exact value from document
private String originalValue;// Exact value from document

private final DOMNode ownerElement;

Expand Down Expand Up @@ -103,10 +103,15 @@ public String getName() {
return name;
}

@Override
public String getNodeValue() throws DOMException {
return getValue();
}

@Override
public String getLocalName() {
int colonIndex = name.indexOf(":");
if(colonIndex > 0) {
if (colonIndex > 0) {
return name.substring(colonIndex + 1);
}
return name;
Expand All @@ -120,6 +125,11 @@ public String getLocalName() {
public DOMElement getOwnerElement() {
return ownerElement.isElement() ? (DOMElement) ownerElement : null;
}

@Override
public DOMDocument getOwnerDocument() {
return ownerElement != null ? ownerElement.getOwnerDocument() : null;
}

/*
*
Expand Down Expand Up @@ -186,6 +196,7 @@ public boolean hasDelimiter() {
* Get original attribute value from the document.
*
* This will include quotations (", ').
*
* @return attribute value with quotations if it had them.
*/
public String getOriginalValue() {
Expand All @@ -200,6 +211,7 @@ public void setValue(String value, int start, int end) {

/**
* Returns a String of 'value' without surrounding quotes if it had them.
*
* @param value
* @return
*/
Expand All @@ -219,6 +231,7 @@ public static String convertToQuotelessValue(String value) {

/**
* Checks if 'value' has matching surrounding quotations.
*
* @param value
* @return
*/
Expand All @@ -231,11 +244,12 @@ public static boolean isQuoted(String value) {
}
char quoteValueStart = value.charAt(0);
boolean start = quoteValueStart == '\"' || quoteValueStart == '\'' ? true : false;
if(start == false) {
if (start == false) {
return false;
}
char quoteValueEnd = value.charAt(value.length() - 1);
boolean end = (quoteValueEnd == '\"' || quoteValueEnd == '\'') && quoteValueEnd == quoteValueStart ? true : false;
boolean end = (quoteValueEnd == '\"' || quoteValueEnd == '\'') && quoteValueEnd == quoteValueStart ? true
: false;
return end;
}

Expand Down Expand Up @@ -292,6 +306,7 @@ public String extractPrefixFromXmlns() {
* Returns the prefix if the given URI matches this attributes value.
*
* If the URI doesnt match, null is returned.
*
* @param uri
* @return
*/
Expand Down Expand Up @@ -320,12 +335,12 @@ public String getPrefixIfMatchesURI(String uri) {
public boolean isNoDefaultXmlns() {
return isNoDefaultXmlns(name);
}

public static boolean isNoDefaultXmlns(String attributeName) {
return attributeName.startsWith(XMLNS_NO_DEFAULT_ATTR);
}

/*
/*
* (non-Javadoc)
*
* @see org.w3c.dom.Node#getNextSibling()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,33 +12,29 @@

import java.util.List;

import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.LocationLink;
import org.eclipse.lsp4j.Position;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4xml.commons.BadLocationException;
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
import org.eclipse.lsp4xml.dom.DOMDocument;
import org.eclipse.lsp4xml.dom.DOMNode;
import org.eclipse.lsp4xml.extensions.references.XMLReferencesManager;
import org.eclipse.lsp4xml.services.extensions.IDefinitionParticipant;
import org.eclipse.lsp4xml.services.extensions.AbstractDefinitionParticipant;
import org.eclipse.lsp4xml.utils.XMLPositionUtility;

public class XMLReferencesDefinitionParticipant implements IDefinitionParticipant {
public class XMLReferencesDefinitionParticipant extends AbstractDefinitionParticipant {

@Override
public void findDefinition(DOMDocument document, Position position, List<Location> locations) {
try {
int offset = document.offsetAt(position);
DOMNode node = document.findNodeAt(offset);
if (node != null) {
XMLReferencesManager.getInstance().collect(node, n -> {
DOMDocument doc = n.getOwnerDocument();
Range range = XMLPositionUtility.createRange(n.getStart(), n.getEnd(), doc);
locations.add(new Location(doc.getDocumentURI(), range));
});
}
} catch (BadLocationException e) {
protected boolean match(DOMDocument document) {
return true;
}

}
@Override
protected void findDefinition(DOMNode origin, Position position, int offset, List<LocationLink> locations,
CancelChecker cancelChecker) {
XMLReferencesManager.getInstance().collect(origin, target -> {
LocationLink location = XMLPositionUtility.createLocationLink(origin, target);
locations.add(location);
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@
import org.eclipse.lsp4xml.extensions.contentmodel.model.ContentModelProvider;
import org.eclipse.lsp4xml.extensions.xsd.contentmodel.CMXSDContentModelProvider;
import org.eclipse.lsp4xml.extensions.xsd.participants.XSDCompletionParticipant;
import org.eclipse.lsp4xml.extensions.xsd.participants.XSDDefinitionParticipant;
import org.eclipse.lsp4xml.extensions.xsd.participants.diagnostics.XSDDiagnosticsParticipant;
import org.eclipse.lsp4xml.services.extensions.ICompletionParticipant;
import org.eclipse.lsp4xml.services.extensions.IDefinitionParticipant;
import org.eclipse.lsp4xml.services.extensions.IXMLExtension;
import org.eclipse.lsp4xml.services.extensions.XMLExtensionsRegistry;
import org.eclipse.lsp4xml.services.extensions.diagnostics.IDiagnosticsParticipant;
Expand All @@ -31,20 +33,23 @@ public class XSDPlugin implements IXMLExtension {

private final ICompletionParticipant completionParticipant;

private final IDefinitionParticipant definitionParticipant;

private final IDiagnosticsParticipant diagnosticsParticipant;

private XSDURIResolverExtension uiResolver;

public XSDPlugin() {
completionParticipant = new XSDCompletionParticipant();
definitionParticipant = new XSDDefinitionParticipant();
diagnosticsParticipant = new XSDDiagnosticsParticipant();
}

@Override
public void doSave(ISaveContext context) {
String documentURI = context.getUri();
DOMDocument document = context.getDocument(documentURI);
if(DOMUtils.isXSD(document)) {
if (DOMUtils.isXSD(document)) {
context.collectDocumentToValidate(d -> {
DOMDocument xml = context.getDocument(d.getDocumentURI());
return xml.usesSchema(context.getUri());
Expand All @@ -63,12 +68,15 @@ public void start(InitializeParams params, XMLExtensionsRegistry registry) {
modelManager.registerModelProvider(modelProvider);
// register completion, diagnostic particpant
registry.registerCompletionParticipant(completionParticipant);
registry.registerDefinitionParticipant(definitionParticipant);
registry.registerDiagnosticsParticipant(diagnosticsParticipant);
}

@Override
public void stop(XMLExtensionsRegistry registry) {
registry.getResolverExtensionManager().unregisterResolver(uiResolver);
registry.unregisterCompletionParticipant(completionParticipant);
registry.unregisterDefinitionParticipant(definitionParticipant);
registry.unregisterDiagnosticsParticipant(diagnosticsParticipant);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*******************************************************************************
* Copyright (c) 2019 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
*
* Contributors:
* Red Hat Inc. - initial API and implementation
*******************************************************************************/
package org.eclipse.lsp4xml.extensions.xsd.participants;

import java.util.List;

import org.eclipse.lsp4j.LocationLink;
import org.eclipse.lsp4j.Position;
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
import org.eclipse.lsp4xml.dom.DOMAttr;
import org.eclipse.lsp4xml.dom.DOMDocument;
import org.eclipse.lsp4xml.dom.DOMNode;
import org.eclipse.lsp4xml.extensions.xsd.utils.XSDUtils;
import org.eclipse.lsp4xml.services.extensions.AbstractDefinitionParticipant;
import org.eclipse.lsp4xml.utils.DOMUtils;
import org.eclipse.lsp4xml.utils.XMLPositionUtility;

/**
* XSD definition which manages teh following definition:
*
* <ul>
* <li>xs:element/@type -> xs:complexType/@name</li> *
* <li>xs:extension/@base -> xs:complexType/@name</li>
* </ul>
*
* @author Angelo ZERR
*
*/
public class XSDDefinitionParticipant extends AbstractDefinitionParticipant {

@Override
protected boolean match(DOMDocument document) {
return DOMUtils.isXSD(document);
}

@Override
protected void findDefinition(DOMNode node, Position position, int offset, List<LocationLink> locations,
CancelChecker cancelChecker) {
// - xs:element/@type -> xs:complexType/@name
// - xs:extension/@base -> xs:complexType/@name
DOMAttr attr = node.findAttrAt(offset);
if (XSDUtils.isBoundToComplexTypes(attr)) {
XSDUtils.collectComplexTypes(attr, true, (targetNamespacePrefix, targetAttr) -> {
LocationLink location = XMLPositionUtility.createLocationLink(attr, targetAttr);
locations.add(location);
});
}
}

}
Loading

0 comments on commit 140a8c7

Please sign in to comment.