diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/XSDPlugin.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/XSDPlugin.java index f102951b1..1abb7b681 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/XSDPlugin.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/XSDPlugin.java @@ -18,11 +18,13 @@ import org.eclipse.lsp4xml.extensions.xsd.participants.XSDCodeLensParticipant; import org.eclipse.lsp4xml.extensions.xsd.participants.XSDCompletionParticipant; import org.eclipse.lsp4xml.extensions.xsd.participants.XSDDefinitionParticipant; +import org.eclipse.lsp4xml.extensions.xsd.participants.XSDHighlightingParticipant; import org.eclipse.lsp4xml.extensions.xsd.participants.XSDReferenceParticipant; import org.eclipse.lsp4xml.extensions.xsd.participants.diagnostics.XSDDiagnosticsParticipant; import org.eclipse.lsp4xml.services.extensions.ICodeLensParticipant; import org.eclipse.lsp4xml.services.extensions.ICompletionParticipant; import org.eclipse.lsp4xml.services.extensions.IDefinitionParticipant; +import org.eclipse.lsp4xml.services.extensions.IHighlightingParticipant; import org.eclipse.lsp4xml.services.extensions.IReferenceParticipant; import org.eclipse.lsp4xml.services.extensions.IXMLExtension; import org.eclipse.lsp4xml.services.extensions.XMLExtensionsRegistry; @@ -42,9 +44,8 @@ public class XSDPlugin implements IXMLExtension { private final IDiagnosticsParticipant diagnosticsParticipant; private final IReferenceParticipant referenceParticipant; - private final ICodeLensParticipant codeLensParticipant; - + private final IHighlightingParticipant highlightingParticipant; private XSDURIResolverExtension uiResolver; public XSDPlugin() { @@ -53,6 +54,7 @@ public XSDPlugin() { diagnosticsParticipant = new XSDDiagnosticsParticipant(); referenceParticipant = new XSDReferenceParticipant(); codeLensParticipant = new XSDCodeLensParticipant(); + highlightingParticipant = new XSDHighlightingParticipant(); } @Override @@ -82,6 +84,7 @@ public void start(InitializeParams params, XMLExtensionsRegistry registry) { registry.registerDiagnosticsParticipant(diagnosticsParticipant); registry.registerReferenceParticipant(referenceParticipant); registry.registerCodeLensParticipant(codeLensParticipant); + registry.registerHighlightingParticipant(highlightingParticipant); } @Override @@ -92,5 +95,6 @@ public void stop(XMLExtensionsRegistry registry) { registry.unregisterDiagnosticsParticipant(diagnosticsParticipant); registry.unregisterReferenceParticipant(referenceParticipant); registry.unregisterCodeLensParticipant(codeLensParticipant); + registry.unregisterHighlightingParticipant(highlightingParticipant); } } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/participants/XSDCodeLensParticipant.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/participants/XSDCodeLensParticipant.java index 61b47a134..5069f303c 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/participants/XSDCodeLensParticipant.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/participants/XSDCodeLensParticipant.java @@ -56,7 +56,7 @@ public void doCodeLens(DOMDocument xmlDocument, List lenses, CancelChe // Add references CodeLens for each xs:simpleType, xs:complexType, xs:element, // xs:group root element. Map cache = new HashMap<>(); - XSDUtils.collectXSReferenceTypes(xmlDocument, (origin, target) -> { + XSDUtils.searchXSOriginAttributes(xmlDocument, (origin, target) -> { // Increment references count Codelens for the given target element DOMElement targetElement = target.getOwnerElement(); CodeLens codeLens = cache.get(targetElement); diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/participants/XSDCompletionParticipant.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/participants/XSDCompletionParticipant.java index 6aac47b69..db31a9a04 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/participants/XSDCompletionParticipant.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/participants/XSDCompletionParticipant.java @@ -54,7 +54,7 @@ public void onAttributeValue(String valuePrefix, ICompletionRequest request, ICo // - @type (ex : xs:element/@type) // - @base (ex : xs:extension/@base) // bound to complextTypes/@name - XSDUtils.collectXSTypes(originAttr, bindingType, false, (targetNamespacePrefix, targetAttr) -> { + XSDUtils.searchXSTargetAttributes(originAttr, bindingType, false, (targetNamespacePrefix, targetAttr) -> { CompletionItem item = new CompletionItem(); item.setDocumentation(new MarkupContent(MarkupKind.MARKDOWN, DataType.getDocumentation(targetAttr))); String value = createComplexTypeValue(targetAttr, targetNamespacePrefix); diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/participants/XSDDefinitionParticipant.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/participants/XSDDefinitionParticipant.java index a2683ac8f..a1fb67d47 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/participants/XSDDefinitionParticipant.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/participants/XSDDefinitionParticipant.java @@ -51,7 +51,7 @@ protected void findDefinition(DOMNode node, Position position, int offset, List< DOMAttr attr = node.findAttrAt(offset); BindingType bindingType = XSDUtils.getBindingType(attr); if (bindingType != BindingType.NONE) { - XSDUtils.collectXSTypes(attr, bindingType, true, (targetNamespacePrefix, targetAttr) -> { + XSDUtils.searchXSTargetAttributes(attr, bindingType, true, (targetNamespacePrefix, targetAttr) -> { LocationLink location = XMLPositionUtility.createLocationLink(attr.getNodeAttrValue(), targetAttr.getNodeAttrValue()); locations.add(location); diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/participants/XSDHighlightingParticipant.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/participants/XSDHighlightingParticipant.java new file mode 100644 index 000000000..7f3cfec2b --- /dev/null +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/participants/XSDHighlightingParticipant.java @@ -0,0 +1,81 @@ +/******************************************************************************* +* 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.DocumentHighlight; +import org.eclipse.lsp4j.DocumentHighlightKind; +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.extensions.xsd.utils.XSDUtils.BindingType; +import org.eclipse.lsp4xml.services.extensions.IHighlightingParticipant; +import org.eclipse.lsp4xml.utils.DOMUtils; +import org.eclipse.lsp4xml.utils.XMLPositionUtility; + +/** + * XSD highlight participant + * + * @author Angelo ZERR + * + */ +public class XSDHighlightingParticipant implements IHighlightingParticipant { + + @Override + public void findDocumentHighlights(DOMNode node, Position position, int offset, List highlights, + CancelChecker cancelChecker) { + // XSD highlight applicable only for XSD file + DOMDocument document = node.getOwnerDocument(); + if (!DOMUtils.isXSD(document)) { + return; + } + // Highlight works ony when attribute is selected (orign or target attribute) + DOMAttr attr = node.findAttrAt(offset); + if (attr == null) { + return; + } + // Try to get the binding from the origin attribute + BindingType bindingType = XSDUtils.getBindingType(attr); + if (bindingType != BindingType.NONE) { + // It's an origin attribute, highlight the origin and target attribute + DOMAttr originAttr = attr; + highlights + .add(new DocumentHighlight(XMLPositionUtility.createRange(originAttr.getNodeAttrValue().getStart(), + originAttr.getNodeAttrValue().getEnd(), document), DocumentHighlightKind.Read)); + // Search target attributes + XSDUtils.searchXSTargetAttributes(originAttr, bindingType, true, (targetNamespacePrefix, targetAttr) -> { + highlights.add(new DocumentHighlight( + XMLPositionUtility.createRange(targetAttr.getNodeAttrValue().getStart(), + targetAttr.getNodeAttrValue().getEnd(), targetAttr.getOwnerDocument()), + DocumentHighlightKind.Write)); + }); + + } else if (XSDUtils.isXSTargetElement(attr.getOwnerElement())) { + // It's an target attribute, highlight all origin attributes linked to this + // target attribute + DOMAttr targetAttr = attr; + highlights.add(new DocumentHighlight( + XMLPositionUtility.createRange(targetAttr.getNodeAttrValue().getStart(), + targetAttr.getNodeAttrValue().getEnd(), targetAttr.getOwnerDocument()), + DocumentHighlightKind.Write)); + XSDUtils.searchXSOriginAttributes(targetAttr, + (origin, target) -> highlights.add(new DocumentHighlight( + XMLPositionUtility.createRange(origin.getNodeAttrValue().getStart(), + origin.getNodeAttrValue().getEnd(), origin.getOwnerDocument()), + DocumentHighlightKind.Read)), + cancelChecker); + } + } + +} diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/participants/XSDReferenceParticipant.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/participants/XSDReferenceParticipant.java index a67434bd2..96947ff05 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/participants/XSDReferenceParticipant.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/participants/XSDReferenceParticipant.java @@ -43,8 +43,9 @@ protected void findReferences(DOMNode node, Position position, int offset, Refer if (attr != null) { node = attr; } - XSDUtils.collectXSReferenceTypes(node, - (from, to) -> locations.add(XMLPositionUtility.createLocation(from.getNodeAttrValue())), cancelChecker); + XSDUtils.searchXSOriginAttributes(node, + (origin, target) -> locations.add(XMLPositionUtility.createLocation(origin.getNodeAttrValue())), + cancelChecker); } } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/utils/XSDUtils.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/utils/XSDUtils.java index 1b8aa774c..69bbf5800 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/utils/XSDUtils.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/xsd/utils/XSDUtils.java @@ -53,15 +53,17 @@ public boolean isComplex() { } /** - * Returns the binding type of the given attribute. + * Returns the binding type of the origin attribute which bounds an another + * target attribute. * - * @param attr the attribute - * @return the binding type of the given attribute. + * @param originAttr the origin attribute + * @return the binding type of the origin attribute which bounds an another + * target attribute. */ - public static BindingType getBindingType(DOMAttr attr) { - String name = attr.getName(); + public static BindingType getBindingType(DOMAttr originAttr) { + String name = originAttr.getName(); if ("type".equals(name)) { - if ("attribute".equals(attr.getOwnerElement().getLocalName())) { + if ("attribute".equals(originAttr.getOwnerElement().getLocalName())) { // - collector) { if (bindingType == BindingType.NONE) { return; @@ -192,12 +190,13 @@ private static boolean isBounded(Element originElement, BindingType originBindin } /** - * Collect references types from the given referenced node. + * Search origin attributes from the given target node.. * * @param targetNode the referenced node - * @param collector the collector to collect reference origin and target node. + * @param collector the collector to collect reference between an origin and + * target attribute. */ - public static void collectXSReferenceTypes(DOMNode targetNode, BiConsumer collector, + public static void searchXSOriginAttributes(DOMNode targetNode, BiConsumer collector, CancelChecker cancelChecker) { // get referenced attribute nodes from the given referenced node List targetAttrs = getTargetAttrs(targetNode); @@ -223,7 +222,7 @@ public static void collectXSReferenceTypes(DOMNode targetNode, BiConsumer getTargetAttrs(DOMNode referencedNode) { case Node.ELEMENT_NODE: // The referenced node is an element, get the attribute name) and add it to // search references from it. - addReferenceNode(referencedNode, referencedNodes); + addTargetNode(referencedNode, referencedNodes); break; case Node.DOCUMENT_NODE: // The referenced node is the DOM document, collect all attributes @@ -252,9 +251,8 @@ private static List getTargetAttrs(DOMNode referencedNode) { Node n = nodes.item(i); if (n.getNodeType() == Node.ELEMENT_NODE) { DOMElement element = (DOMElement) n; - if (isXSComplexType(element) || isXSSimpleType(element) || isXSElement(element) - || isXSGroup(element)) { - addReferenceNode(element, referencedNodes); + if (isXSTargetElement(element)) { + addTargetNode(element, referencedNodes); } } } @@ -268,7 +266,7 @@ private static List getTargetAttrs(DOMNode referencedNode) { * @param node the node to add. * @param targetAttrs the list of referenced nodes. */ - private static void addReferenceNode(DOMNode node, List targetAttrs) { + private static void addTargetNode(DOMNode node, List targetAttrs) { DOMAttr attr = null; switch (node.getNodeType()) { case Node.ATTRIBUTE_NODE: @@ -284,7 +282,7 @@ private static void addReferenceNode(DOMNode node, List targetAttrs) { } } - private static void collectXSReferenceTypes(NodeList nodes, List targetAttrs, String targetNamespacePrefix, + private static void searchXSOriginAttributes(NodeList nodes, List targetAttrs, String targetNamespacePrefix, BiConsumer collector, CancelChecker cancelChecker) { for (int i = 0; i < nodes.getLength(); i++) { if (cancelChecker != null) { @@ -315,7 +313,7 @@ private static void collectXSReferenceTypes(NodeList nodes, List target } } if (node.hasChildNodes()) { - collectXSReferenceTypes(node.getChildNodes(), targetAttrs, targetNamespacePrefix, collector, + searchXSOriginAttributes(node.getChildNodes(), targetAttrs, targetNamespacePrefix, collector, cancelChecker); } } @@ -337,4 +335,8 @@ public static boolean isXSElement(Element element) { public static boolean isXSGroup(Element element) { return "group".equals(element.getLocalName()); } + + public static boolean isXSTargetElement(Element element) { + return isXSComplexType(element) || isXSSimpleType(element) || isXSElement(element) || isXSGroup(element); + } } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/XMLHighlighting.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/XMLHighlighting.java index 8ed1b8126..ac6df96d9 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/XMLHighlighting.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/XMLHighlighting.java @@ -30,6 +30,7 @@ import org.eclipse.lsp4xml.dom.DOMElement; import org.eclipse.lsp4xml.dom.DOMNode; import org.eclipse.lsp4xml.dom.parser.TokenType; +import org.eclipse.lsp4xml.services.extensions.IHighlightingParticipant; import org.eclipse.lsp4xml.services.extensions.XMLExtensionsRegistry; /** @@ -56,10 +57,22 @@ public List findDocumentHighlights(DOMDocument xmlDocument, P return Collections.emptyList(); } DOMNode node = xmlDocument.findNodeAt(offset); - if (node == null || !node.isElement() || ((DOMElement) node).getTagName() == null) { + if (node == null) { return Collections.emptyList(); } + List highlights = new ArrayList<>(); + fillWithDefaultHighlights(node, position, offset, highlights, cancelChecker); + fillWithCustomHighlights(node, position, offset, highlights, cancelChecker); + return highlights; + } + + private static void fillWithDefaultHighlights(DOMNode node, Position position, int offset, + List highlights, CancelChecker cancelChecker) { + if (!node.isElement() || ((DOMElement) node).getTagName() == null) { + return; + } + DOMDocument xmlDocument = node.getOwnerDocument(); Range startTagRange = null; Range endTagRange = null; if (node.isCDATA()) { @@ -73,16 +86,15 @@ public List findDocumentHighlights(DOMDocument xmlDocument, P } catch (BadLocationException e) { LOGGER.log(Level.SEVERE, "In XMLHighlighting the Node at provided Offset is a BadLocation", e); - return Collections.emptyList(); + return; } if (covers(tempRange, position)) { startPos.setCharacter(startPos.getCharacter() + 1); // {Cursor} <{Cursor}![CDATA[ endPos.setCharacter(endPos.getCharacter() - 1); // ]]>{Cursor} -> ]]{Cursor}> Position startPosEnd = new Position(startPos.getLine(), startPos.getCharacter() + 8); Position endPosStart = new Position(endPos.getLine(), endPos.getCharacter() - 2); - return getHighlightsList(new Range(startPos, startPosEnd), new Range(endPosStart, endPos)); + fillHighlightsList(new Range(startPos, startPosEnd), new Range(endPosStart, endPos), highlights); } - return Collections.emptyList(); } else if (node.isElement()) { DOMElement element = (DOMElement) node; startTagRange = getTagNameRange(TokenType.StartTag, node.getStart(), xmlDocument); @@ -90,22 +102,25 @@ public List findDocumentHighlights(DOMDocument xmlDocument, P ? getTagNameRange(TokenType.EndTag, element.getEndTagOpenOffset(), xmlDocument) : null; if (doesTagCoverPosition(startTagRange, endTagRange, position)) { - return getHighlightsList(startTagRange, endTagRange); + fillHighlightsList(startTagRange, endTagRange, highlights); } } - return Collections.emptyList(); } - private static List getHighlightsList(Range startTagRange, Range endTagRange) { - - List result = new ArrayList<>(2); + private static void fillHighlightsList(Range startTagRange, Range endTagRange, List result) { if (startTagRange != null) { result.add(new DocumentHighlight(startTagRange, DocumentHighlightKind.Read)); } if (endTagRange != null) { result.add(new DocumentHighlight(endTagRange, DocumentHighlightKind.Read)); } - return result; } + private void fillWithCustomHighlights(DOMNode node, Position position, int offset, + List highlights, CancelChecker cancelChecker) { + // Consume highlighting participant + for (IHighlightingParticipant highlightingParticipant : extensionsRegistry.getHighlightingParticipants()) { + highlightingParticipant.findDocumentHighlights(node, position, offset,highlights, cancelChecker); + } + } } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/extensions/IHighlightingParticipant.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/extensions/IHighlightingParticipant.java new file mode 100644 index 000000000..27aac85a5 --- /dev/null +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/extensions/IHighlightingParticipant.java @@ -0,0 +1,15 @@ +package org.eclipse.lsp4xml.services.extensions; + +import java.util.List; + +import org.eclipse.lsp4j.DocumentHighlight; +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.jsonrpc.CancelChecker; +import org.eclipse.lsp4xml.dom.DOMNode; + +public interface IHighlightingParticipant { + + void findDocumentHighlights(DOMNode node, Position position, int offset, List highlights, + CancelChecker cancelChecker); + +} diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/extensions/XMLExtensionsRegistry.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/extensions/XMLExtensionsRegistry.java index e636bf3ac..088baf02d 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/extensions/XMLExtensionsRegistry.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/extensions/XMLExtensionsRegistry.java @@ -43,6 +43,7 @@ public class XMLExtensionsRegistry implements IComponentProvider { private final List definitionParticipants; private final List referenceParticipants; private final List codeLensParticipants; + private final List highlightingParticipants; private IXMLDocumentProvider documentProvider; @@ -64,6 +65,7 @@ public XMLExtensionsRegistry() { definitionParticipants = new ArrayList<>(); referenceParticipants = new ArrayList<>(); codeLensParticipants = new ArrayList<>(); + highlightingParticipants = new ArrayList<>(); resolverExtensionManager = new URIResolverExtensionManager(); components = new HashMap<>(); registerComponent(resolverExtensionManager); @@ -139,6 +141,11 @@ public Collection getCodeLensParticipants() { return codeLensParticipants; } + public Collection getHighlightingParticipants() { + initializeIfNeeded(); + return highlightingParticipants; + } + public void initializeIfNeeded() { if (initialized) { return; @@ -238,6 +245,14 @@ public void unregisterCodeLensParticipant(ICodeLensParticipant codeLensParticipa codeLensParticipants.add(codeLensParticipant); } + public void registerHighlightingParticipant(IHighlightingParticipant highlightingParticipant) { + highlightingParticipants.add(highlightingParticipant); + } + + public void unregisterHighlightingParticipant(IHighlightingParticipant highlightingParticipant) { + highlightingParticipants.add(highlightingParticipant); + } + /** * Returns the XML Document provider and null otherwise. * diff --git a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/XMLAssert.java b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/XMLAssert.java index b21397c2c..13f43299f 100644 --- a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/XMLAssert.java +++ b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/XMLAssert.java @@ -30,6 +30,8 @@ import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.CompletionList; import org.eclipse.lsp4j.Diagnostic; +import org.eclipse.lsp4j.DocumentHighlight; +import org.eclipse.lsp4j.DocumentHighlightKind; import org.eclipse.lsp4j.DocumentLink; import org.eclipse.lsp4j.DocumentSymbol; import org.eclipse.lsp4j.Hover; @@ -743,10 +745,77 @@ public static void assertCodeLens(List actual, CodeLens... e Command expectedCommand = expected[i].getCommand(); Command actualCommand = actual.get(i).getCommand(); if (expectedCommand != null && actualCommand != null) { - Assert.assertEquals(expectedCommand.getTitle(), actualCommand.getTitle()); + Assert.assertEquals(expectedCommand.getTitle(), actualCommand.getTitle()); Assert.assertEquals(expectedCommand.getCommand(), actualCommand.getCommand()); } Assert.assertEquals(expected[i].getData(), actual.get(i).getData()); } } + + // ------------------- Highlights assert + + public static void testHighlightsFor(String xml, DocumentHighlight... expected) throws BadLocationException { + testHighlightsFor(xml, null, expected); + } + + public static void testHighlightsFor(String value, String fileURI, DocumentHighlight... expected) + throws BadLocationException { + int offset = value.indexOf('|'); + value = value.substring(0, offset) + value.substring(offset + 1); + + TextDocument document = new TextDocument(value, fileURI != null ? fileURI : "test://test/test.xml"); + Position position = document.positionAt(offset); + + XMLLanguageService xmlLanguageService = new XMLLanguageService(); + + ContentModelSettings settings = new ContentModelSettings(); + settings.setUseCache(false); + xmlLanguageService.doSave(new SettingsSaveContext(settings)); + + DOMDocument xmlDocument = DOMParser.getInstance().parse(document, + xmlLanguageService.getResolverExtensionManager()); + xmlLanguageService.setDocumentProvider((uri) -> xmlDocument); + + List actual = xmlLanguageService.findDocumentHighlights(xmlDocument, position, + () -> { + }); + assertDocumentHighlight(actual, expected); + } + + public static void assertDocumentHighlight(List actual, + DocumentHighlight... expected) { + Assert.assertEquals(expected.length, actual.size()); + Assert.assertArrayEquals(expected, actual.toArray()); + } + + public static DocumentHighlight hl(Range range) { + return hl(range, DocumentHighlightKind.Read); + } + + public static DocumentHighlight hl(Range range, DocumentHighlightKind kind) { + return new DocumentHighlight(range, kind); + } + + public static void assertHighlights(String value, int[] expectedMatches, String elementName) + throws BadLocationException { + int offset = value.indexOf("|"); + value = value.substring(0, offset) + value.substring(offset + 1); + + DOMDocument document = DOMParser.getInstance().parse(value, "test://test/test.html", null); + + Position position = document.positionAt(offset); + + XMLLanguageService languageService = new XMLLanguageService(); + List highlights = languageService.findDocumentHighlights(document, position); + Assert.assertEquals(expectedMatches.length, highlights.size()); + for (int i = 0; i < highlights.size(); i++) { + DocumentHighlight highlight = highlights.get(i); + int actualStartOffset = document.offsetAt(highlight.getRange().getStart()); + Assert.assertEquals(expectedMatches[i], actualStartOffset); + int actualEndOffset = document.offsetAt(highlight.getRange().getEnd()); + Assert.assertEquals(expectedMatches[i] + (elementName != null ? elementName.length() : 0), actualEndOffset); + Assert.assertEquals(elementName, + document.getText().substring(actualStartOffset, actualEndOffset).toLowerCase()); + } + } } \ No newline at end of file diff --git a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/xsd/XSDDefinitionExtensionsTest.java b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/xsd/XSDDefinitionExtensionsTest.java index d1c7165e0..755819cd4 100644 --- a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/xsd/XSDDefinitionExtensionsTest.java +++ b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/xsd/XSDDefinitionExtensionsTest.java @@ -18,7 +18,7 @@ import org.junit.Test; /** - * XSD definition tests. + * XSD highlighting tests. * * @author Angelo ZERR */ diff --git a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/xsd/XSDHighlightingExtensionsTest.java b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/xsd/XSDHighlightingExtensionsTest.java new file mode 100644 index 000000000..3d8a6abe5 --- /dev/null +++ b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/xsd/XSDHighlightingExtensionsTest.java @@ -0,0 +1,139 @@ +/******************************************************************************* +* 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; + +import static org.eclipse.lsp4j.DocumentHighlightKind.Read; +import static org.eclipse.lsp4j.DocumentHighlightKind.Write; +import static org.eclipse.lsp4xml.XMLAssert.hl; +import static org.eclipse.lsp4xml.XMLAssert.r; +import static org.eclipse.lsp4xml.XMLAssert.testHighlightsFor; + +import org.eclipse.lsp4xml.commons.BadLocationException; +import org.junit.Test; + +/** + * XSD Highlighting tests. + * + * @author Angelo ZERR + */ +public class XSDHighlightingExtensionsTest { + + @Test + public void highlightingOnElementType() throws BadLocationException { + // highlighting on xs:element/@type + String xml = "\r\n" + // + "\r\n" + + // + " \r\n" + // <- set cursor at xs:element/@type + // attribute + " \r\n" + // <- xs:complexType/@name is highlighted + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + "\r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + ""; + testHighlightsFor(xml, hl(r(2, 29, 2, 46), Read), hl(r(3, 22, 3, 36), Write)); + } + + @Test + public void highlightingOnElementType2() throws BadLocationException { + // highlighting on xs:element/@type + String xml = "\r\n" + // + "\r\n" + + // + " \r\n" + // <- set cursor at xs:element/@type + // attribute + " \r\n" + // <- xs:complexType/@name is highlighted + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + "\r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + ""; + testHighlightsFor(xml, hl(r(2, 29, 2, 46), Read), hl(r(3, 22, 3, 36), Write)); + } + + @Test + public void highlightingOnComplexTypeName() throws BadLocationException { + // highlighting on xs:complexType/@name + String xml = "\r\n" + // + "\r\n" + + // + " \r\n" + // <- + " \r\n" + // <- set cursor at xs:complexType/@name + // attribute + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + "\r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + ""; + testHighlightsFor(xml, hl(r(3, 22, 3, 36), Write), hl(r(2, 29, 2, 46), Read), hl(r(11, 22, 11, 39), Read)); + } + + @Test + public void highlightingOnSimpleTypeName() throws BadLocationException { + // highlighting on xs:simpleType/@name + String xml = "\r\n" + // + "\r\n" + + // + " \r\n" + // <- + " \r\n" + // + // attribute + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + "\r\n" + // + " \r\n" + // <- set cursor at xs:simpleType/@name + " \r\n" + // + " \r\n" + // + " \r\n" + // + ""; + testHighlightsFor(xml, hl(r(15, 21, 15, 35), Write), hl(r(5, 22, 5, 39), Read)); + } +} diff --git a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/services/XMLHighlightingTest.java b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/services/XMLHighlightingTest.java index 34b5afc02..b06716e0e 100644 --- a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/services/XMLHighlightingTest.java +++ b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/services/XMLHighlightingTest.java @@ -10,30 +10,16 @@ */ package org.eclipse.lsp4xml.services; -import java.util.List; +import static org.eclipse.lsp4xml.XMLAssert.assertHighlights; -import org.eclipse.lsp4j.DocumentHighlight; -import org.eclipse.lsp4j.Position; import org.eclipse.lsp4xml.commons.BadLocationException; -import org.eclipse.lsp4xml.dom.DOMDocument; -import org.eclipse.lsp4xml.dom.DOMParser; -import org.junit.Assert; -import org.junit.Before; import org.junit.Test; - /** * XML highlighting services tests * */ public class XMLHighlightingTest { - private XMLLanguageService languageService; - - @Before - public void initializeLanguageService() { - languageService = new XMLLanguageService(); - } - @Test public void single() throws BadLocationException { assertHighlights("|", new int[] {}, null); @@ -83,26 +69,4 @@ public void insideEndTag() throws BadLocationException { assertHighlights("", new int[] { 1, 15 }, "html"); } - private void assertHighlights(String value, int[] expectedMatches, String elementName) throws BadLocationException { - int offset = value.indexOf("|"); - value = value.substring(0, offset) + value.substring(offset + 1); - - DOMDocument document = DOMParser.getInstance().parse(value, "test://test/test.html", null); - - Position position = document.positionAt(offset); - // XMLDocument htmlDoc = ls.parseHTMLDocument(document); - - List highlights = languageService.findDocumentHighlights(document, position); - Assert.assertEquals(expectedMatches.length, highlights.size()); - for (int i = 0; i < highlights.size(); i++) { - DocumentHighlight highlight = highlights.get(i); - int actualStartOffset = document.offsetAt(highlight.getRange().getStart()); - Assert.assertEquals(expectedMatches[i], actualStartOffset); - int actualEndOffset = document.offsetAt(highlight.getRange().getEnd()); - Assert.assertEquals(expectedMatches[i] + (elementName != null ? elementName.length() : 0), actualEndOffset); - Assert.assertEquals(elementName, - document.getText().substring(actualStartOffset, actualEndOffset).toLowerCase()); - } - } - }