From 0f276b8761611298b23ae398da73c66b93fd9c0f Mon Sep 17 00:00:00 2001 From: azerr Date: Mon, 22 Jul 2019 17:41:10 +0200 Subject: [PATCH] Completion should support markdown for documentation Fix #526 Signed-off-by: azerr --- .../ContentModelCompletionParticipant.java | 46 +++--- .../ContentModelHoverParticipant.java | 60 ++++---- .../contentmodel/utils/XMLGenerator.java | 74 +++++++++- .../lsp4xml/services/CompletionRequest.java | 12 +- .../lsp4xml/services/HoverRequest.java | 6 + .../extensions/ICompletionRequest.java | 6 +- .../services/extensions/IHoverRequest.java | 3 +- .../lsp4xml/utils/MarkupContentFactory.java | 60 ++++++++ .../java/org/eclipse/lsp4xml/XMLAssert.java | 18 ++- .../DTDCompletionExtensionsTest.java | 5 +- .../XMLSchemaCompletionExtensionsTest.java | 95 +++++++++++- .../XMLSchemaHoverExtensionsTest.java | 139 ++++++++++-------- .../xsd/XSDCompletionExtensionsTest.java | 11 +- 13 files changed, 392 insertions(+), 143 deletions(-) create mode 100644 org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/utils/MarkupContentFactory.java diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/participants/ContentModelCompletionParticipant.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/participants/ContentModelCompletionParticipant.java index 26e67528a..12d24841b 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/participants/ContentModelCompletionParticipant.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/participants/ContentModelCompletionParticipant.java @@ -15,6 +15,7 @@ import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.CompletionItemKind; import org.eclipse.lsp4j.InsertTextFormat; +import org.eclipse.lsp4j.MarkupContent; import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.TextEdit; import org.eclipse.lsp4xml.commons.BadLocationException; @@ -42,7 +43,6 @@ public class ContentModelCompletionParticipant extends CompletionParticipantAdap public void onTagOpen(ICompletionRequest request, ICompletionResponse response) throws Exception { try { DOMDocument document = request.getXMLDocument(); - String schemaURI; ContentModelManager contentModelManager = request.getComponent(ContentModelManager.class); DOMElement parentElement = request.getParentElement(); if (parentElement == null) { @@ -51,9 +51,7 @@ public void onTagOpen(ICompletionRequest request, ICompletionResponse response) // XML Schema is done with pattern and not with XML root element) CMDocument cmDocument = contentModelManager.findCMDocument(document, null); if (cmDocument != null) { - schemaURI = cmDocument.getURI(); - fillWithChildrenElementDeclaration(null, cmDocument.getElements(), null, false, request, response, - schemaURI); + fillWithChildrenElementDeclaration(null, cmDocument.getElements(), null, false, request, response); } return; } @@ -62,14 +60,14 @@ public void onTagOpen(ICompletionRequest request, ICompletionResponse response) final CMDocument cmRootDocument = contentModelManager.findCMDocument(parentElement, parentElement.getNamespaceURI()); - schemaURI = cmRootDocument != null ? cmRootDocument.getURI() : null; CMElementDeclaration cmElement = contentModelManager.findCMElement(parentElement); String defaultPrefix = null; if (cmElement != null) { defaultPrefix = parentElement.getPrefix(); - fillWithChildrenElementDeclaration(parentElement, cmElement.getPossibleElements(parentElement, request.getOffset()), - defaultPrefix, false, request, response, schemaURI); + fillWithChildrenElementDeclaration(parentElement, + cmElement.getPossibleElements(parentElement, request.getOffset()), defaultPrefix, false, + request, response); } if (parentElement.isDocumentElement()) { // completion on root document element @@ -85,7 +83,7 @@ public void onTagOpen(ICompletionRequest request, ICompletionResponse response) CMDocument cmDocument = contentModelManager.findCMDocument(parentElement, namespaceURI); if (cmDocument != null) { fillWithChildrenElementDeclaration(parentElement, cmDocument.getElements(), prefix, true, - request, response, cmRootDocument.getURI()); + request, response); } } } @@ -96,8 +94,8 @@ public void onTagOpen(ICompletionRequest request, ICompletionResponse response) if (cmInternalElement != null) { defaultPrefix = parentElement.getPrefix(); fillWithChildrenElementDeclaration(parentElement, - cmInternalElement.getPossibleElements(parentElement, request.getOffset()), defaultPrefix, false, request, - response, schemaURI); + cmInternalElement.getPossibleElements(parentElement, request.getOffset()), defaultPrefix, false, + request, response); } } catch (CacheResourceDownloadingException e) { // XML Schema, DTD is loading, ignore this error @@ -105,8 +103,8 @@ public void onTagOpen(ICompletionRequest request, ICompletionResponse response) } private void fillWithChildrenElementDeclaration(DOMElement element, Collection cmElements, - String p, boolean forceUseOfPrefix, ICompletionRequest request, ICompletionResponse response, - String schemaURI) throws BadLocationException { + String p, boolean forceUseOfPrefix, ICompletionRequest request, ICompletionResponse response) + throws BadLocationException { XMLGenerator generator = request.getXMLGenerator(); for (CMElementDeclaration child : cmElements) { String prefix = forceUseOfPrefix ? p : (element != null ? element.getPrefix(child.getNamespace()) : null); @@ -114,10 +112,8 @@ private void fillWithChildrenElementDeclaration(DOMElement element, Collection 0) { - String markdown = MarkdownConverter.convert(doc); - MarkupContent content = new MarkupContent(); - content.setKind(MarkupKind.MARKDOWN); - content.setValue(markdown); + MarkupContent content = XMLGenerator.createMarkupContent(cmElement, hoverRequest); + if (content != null) { return new Hover(content, hoverRequest.getTagRange()); } } } catch (CacheResourceDownloadingException e) { - return getCacheWarningHover(e); + return getCacheWarningHover(e, hoverRequest); } return null; } @Override public Hover onAttributeName(IHoverRequest hoverRequest) throws Exception { - DOMAttr attribute = (DOMAttr) hoverRequest.getNode(); - try { ContentModelManager contentModelManager = hoverRequest.getComponent(ContentModelManager.class); CMElementDeclaration cmElement = contentModelManager.findCMElement(attribute.getOwnerElement()); @@ -64,17 +60,14 @@ public Hover onAttributeName(IHoverRequest hoverRequest) throws Exception { String attributeName = attribute.getName(); CMAttributeDeclaration cmAttribute = cmElement.findCMAttribute(attributeName); if (cmAttribute != null) { - String doc = cmAttribute.getDocumentation(); - if (doc != null && doc.length() > 0) { - MarkupContent content = new MarkupContent(); - content.setKind(MarkupKind.PLAINTEXT); - content.setValue(doc); - return new Hover(content); + MarkupContent content = XMLGenerator.createMarkupContent(cmAttribute, cmElement, hoverRequest); + if (content != null) { + return new Hover(content, hoverRequest.getTagRange()); } } } } catch (CacheResourceDownloadingException e) { - return getCacheWarningHover(e); + return getCacheWarningHover(e, hoverRequest); } return null; } @@ -83,44 +76,41 @@ public Hover onAttributeName(IHoverRequest hoverRequest) throws Exception { public Hover onAttributeValue(IHoverRequest hoverRequest) throws Exception { DOMAttr attribute = (DOMAttr) hoverRequest.getNode(); - //Attempts to compute specifically for XSI related attributes since - //the XSD itself does not have enough information. Should create a mock XSD eventually. + // Attempts to compute specifically for XSI related attributes since + // the XSD itself does not have enough information. Should create a mock XSD + // eventually. Hover temp = XSISchemaModel.computeHoverResponse(attribute, hoverRequest); - if(temp != null) { + if (temp != null) { return temp; } - + try { ContentModelManager contentModelManager = hoverRequest.getComponent(ContentModelManager.class); - CMElementDeclaration cmElement = contentModelManager.findCMElement(attribute.getOwnerElement()); if (cmElement != null) { String attributeName = attribute.getName(); CMAttributeDeclaration cmAttribute = cmElement.findCMAttribute(attributeName); - + String attributeValue = attribute.getValue(); if (cmAttribute != null) { - String doc = cmAttribute.getValueDocumentation(attributeValue); - if (doc != null && doc.length() > 0) { - String markdown = MarkdownConverter.convert(doc); - MarkupContent content = new MarkupContent(); - content.setKind(MarkupKind.MARKDOWN); - content.setValue(markdown); - return new Hover(content); + MarkupContent content = XMLGenerator.createMarkupContent(cmAttribute, attributeValue, cmElement, + hoverRequest); + if (content != null) { + return new Hover(content, hoverRequest.getTagRange()); } } } } catch (CacheResourceDownloadingException e) { - return getCacheWarningHover(e); + return getCacheWarningHover(e, hoverRequest); } return null; } - private Hover getCacheWarningHover(CacheResourceDownloadingException e) { + private static Hover getCacheWarningHover(CacheResourceDownloadingException e, IMarkupKindSupport support) { // Here cache is enabled and some XML Schema, DTD, etc are loading - MarkupContent content = new MarkupContent(); - content.setKind(MarkupKind.MARKDOWN); - content.setValue("Cannot process " + (e.isDTD() ? "DTD" : "XML Schema") + " hover: " + e.getMessage()); + MarkupContent content = MarkupContentFactory.createMarkupContent( + "Cannot process " + (e.isDTD() ? "DTD" : "XML Schema") + " hover: " + e.getMessage(), + MarkupKind.MARKDOWN, support); return new Hover(content); } } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/utils/XMLGenerator.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/utils/XMLGenerator.java index 450c4c550..9de11bc1f 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/utils/XMLGenerator.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/utils/XMLGenerator.java @@ -14,12 +14,14 @@ import java.util.Collection; import java.util.List; +import org.eclipse.lsp4j.MarkupContent; +import org.eclipse.lsp4j.MarkupKind; import org.eclipse.lsp4xml.commons.SnippetsBuilder; import org.eclipse.lsp4xml.extensions.contentmodel.model.CMAttributeDeclaration; import org.eclipse.lsp4xml.extensions.contentmodel.model.CMElementDeclaration; -import org.eclipse.lsp4xml.settings.SharedSettings; import org.eclipse.lsp4xml.settings.XMLFormattingOptions; -import org.eclipse.lsp4xml.utils.StringUtils; +import org.eclipse.lsp4xml.utils.MarkupContentFactory; +import org.eclipse.lsp4xml.utils.MarkupContentFactory.IMarkupKindSupport; import org.eclipse.lsp4xml.utils.XMLBuilder; /** @@ -223,15 +225,27 @@ public static String generateAttributeValue(String defaultValue, Collection"); + } doc.append("Source: "); + if (html) { + doc.append(""); + } doc.append(getFileName(schemaURI)); + if (html) { + doc.append(""); + doc.append("

"); + } } return doc.length() > 0 ? doc.toString() : null; } @@ -253,4 +267,58 @@ private static String getFileName(String schemaURI) { return schemaURI.substring(index + 1, schemaURI.length()); } + /** + * Returns a markup content for element documentation and null otherwise. + * + * @param cmElement + * @param support + * @return a markup content for element documentation and null otherwise. + */ + public static MarkupContent createMarkupContent(CMElementDeclaration cmElement, IMarkupKindSupport support) { + String documentation = XMLGenerator.generateDocumentation(cmElement.getDocumentation(), + cmElement.getDocumentURI(), support.canSupportMarkupKind(MarkupKind.MARKDOWN)); + if (documentation != null) { + return MarkupContentFactory.createMarkupContent(documentation, MarkupKind.MARKDOWN, support); + } + return null; + } + + /** + * Returns a markup content for attribute name documentation and null otherwise. + * + * @param cmAttribute + * @param ownerElement + * @param support + * @return a markup content for attribute name documentation and null otherwise. + */ + public static MarkupContent createMarkupContent(CMAttributeDeclaration cmAttribute, + CMElementDeclaration ownerElement, IMarkupKindSupport support) { + String documentation = XMLGenerator.generateDocumentation(cmAttribute.getDocumentation(), + ownerElement.getDocumentURI(), support.canSupportMarkupKind(MarkupKind.MARKDOWN)); + if (documentation != null) { + return MarkupContentFactory.createMarkupContent(documentation, MarkupKind.MARKDOWN, support); + } + return null; + } + + /** + * Returns a markup content for attribute value documentation and null + * otherwise. + * + * @param cmAttribute + * @param attributeValue + * @param ownerElement + * @param support + * @return a markup content for attribute value documentation and null + * otherwise. + */ + public static MarkupContent createMarkupContent(CMAttributeDeclaration cmAttribute, String attributeValue, + CMElementDeclaration ownerElement, IMarkupKindSupport support) { + String documentation = XMLGenerator.generateDocumentation(cmAttribute.getValueDocumentation(attributeValue), + ownerElement.getDocumentURI(), support.canSupportMarkupKind(MarkupKind.MARKDOWN)); + if (documentation != null) { + return MarkupContentFactory.createMarkupContent(documentation, MarkupKind.MARKDOWN, support); + } + return null; + } } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/CompletionRequest.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/CompletionRequest.java index 56403b8cd..2111dc0a3 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/CompletionRequest.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/CompletionRequest.java @@ -122,4 +122,14 @@ private String getQuotation() { String quotation = formattingSettings != null ? formattingSettings.getQuotationAsString() : null; return StringUtils.isEmpty(quotation) ? XMLFormattingOptions.DEFAULT_QUOTATION : quotation; } -} + + @Override + public boolean canSupportMarkupKind(String kind) { + return completionSettings != null && completionSettings.getCompletionCapabilities() != null + && completionSettings.getCompletionCapabilities().getCompletionItem() != null + && completionSettings.getCompletionCapabilities().getCompletionItem().getDocumentationFormat() != null + && completionSettings.getCompletionCapabilities().getCompletionItem().getDocumentationFormat() + .contains(kind); + } + +} \ No newline at end of file diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/HoverRequest.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/HoverRequest.java index 1d02d1e60..970874632 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/HoverRequest.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/HoverRequest.java @@ -71,4 +71,10 @@ public void setOpen(boolean open) { public T getComponent(Class clazz) { return extensionsRegistry.getComponent(clazz); } + + @Override + public boolean canSupportMarkupKind(String kind) { + // FIXME : use the hover capability to know if the given kind is supported + return true; + } } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/extensions/ICompletionRequest.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/extensions/ICompletionRequest.java index f962d04a8..dfd437efe 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/extensions/ICompletionRequest.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/extensions/ICompletionRequest.java @@ -14,12 +14,13 @@ import org.eclipse.lsp4xml.commons.BadLocationException; import org.eclipse.lsp4xml.extensions.contentmodel.utils.XMLGenerator; import org.eclipse.lsp4xml.settings.XMLFormattingOptions; +import org.eclipse.lsp4xml.utils.MarkupContentFactory.IMarkupKindSupport; /** * Completion request API. * */ -public interface ICompletionRequest extends IPositionRequest { +public interface ICompletionRequest extends IPositionRequest, IMarkupKindSupport { Range getReplaceRange(); @@ -32,5 +33,4 @@ public interface ICompletionRequest extends IPositionRequest { String getFilterForStartTagName(String tagName); String getInsertAttrValue(String value); - -} +} \ No newline at end of file diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/extensions/IHoverRequest.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/extensions/IHoverRequest.java index ef3147240..1f349691d 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/extensions/IHoverRequest.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/extensions/IHoverRequest.java @@ -11,12 +11,13 @@ package org.eclipse.lsp4xml.services.extensions; import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4xml.utils.MarkupContentFactory.IMarkupKindSupport; /** * Hover request API. * */ -public interface IHoverRequest extends IPositionRequest { +public interface IHoverRequest extends IPositionRequest, IMarkupKindSupport { Range getTagRange(); diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/utils/MarkupContentFactory.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/utils/MarkupContentFactory.java new file mode 100644 index 000000000..05b5d7157 --- /dev/null +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/utils/MarkupContentFactory.java @@ -0,0 +1,60 @@ +/******************************************************************************* +* 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.utils; + +import org.eclipse.lsp4j.MarkupContent; +import org.eclipse.lsp4j.MarkupKind; + +/** + * Factory to create LSP4J {@link MarkupContent} + * + * @author Angelo ZERR + * + */ +public class MarkupContentFactory { + + public static interface IMarkupKindSupport { + + /** + * Returns true if the client can support the given Markup kind for + * documentation and false otherwise. + * + * @param kind the markup kind + * @return true if the client can support the given Markup kind for + * documentation and false otherwise. + */ + boolean canSupportMarkupKind(String kind); + } + + /** + * Create the markup content according the given markup kind and the capability + * of the client. + * + * @param value the documentation value + * @param preferredKind the preferred markup kind + * @return the markup content according the given markup kind and the capability + * of the client. + */ + public static MarkupContent createMarkupContent(String value, String preferredKind, IMarkupKindSupport support) { + if (value == null) { + return null; + } + MarkupContent content = new MarkupContent(); + if (MarkupKind.MARKDOWN.equals(preferredKind) && support.canSupportMarkupKind(preferredKind)) { + String markdown = MarkdownConverter.convert(value); + content.setValue(markdown); + content.setKind(MarkupKind.MARKDOWN); + } else { + content.setValue(value); + content.setKind(MarkupKind.PLAINTEXT); + } + return content; + } +} 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 72707d897..e7dfea284 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 @@ -39,6 +39,7 @@ import org.eclipse.lsp4j.LocationLink; import org.eclipse.lsp4j.MarkedString; import org.eclipse.lsp4j.MarkupContent; +import org.eclipse.lsp4j.MarkupKind; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.PublishDiagnosticsParams; import org.eclipse.lsp4j.Range; @@ -217,18 +218,27 @@ private static void assertCompletion(CompletionList completions, CompletionItem Assert.assertEquals(expected.getFilterText(), match.getFilterText()); } - if (expected.getDetail() != null) { - Assert.assertEquals(expected.getDetail(), match.getDetail()); + if (expected.getDocumentation() != null) { + Assert.assertEquals(expected.getDocumentation(), match.getDocumentation()); } } - public static CompletionItem c(String label, TextEdit textEdit, String filterText, String detail) { + public static CompletionItem c(String label, TextEdit textEdit, String filterText, String documentation) { + return c(label, textEdit, filterText, documentation, null); + } + + public static CompletionItem c(String label, TextEdit textEdit, String filterText, String documentation, + String kind) { CompletionItem item = new CompletionItem(); item.setLabel(label); item.setFilterText(filterText); item.setTextEdit(textEdit); - item.setDetail(detail); + if (kind == null) { + item.setDocumentation(documentation); + } else { + item.setDocumentation(new MarkupContent(kind, documentation)); + } return item; } diff --git a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/contentmodel/DTDCompletionExtensionsTest.java b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/contentmodel/DTDCompletionExtensionsTest.java index 1cccbddc1..94ae043cc 100644 --- a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/contentmodel/DTDCompletionExtensionsTest.java +++ b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/contentmodel/DTDCompletionExtensionsTest.java @@ -6,6 +6,7 @@ import org.eclipse.lsp4j.CompletionCapabilities; import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.CompletionItemCapabilities; +import org.eclipse.lsp4j.MarkupKind; import org.eclipse.lsp4xml.XMLAssert; import org.eclipse.lsp4xml.commons.BadLocationException; import org.eclipse.lsp4xml.services.XMLLanguageService; @@ -45,7 +46,7 @@ public void completionWithChoiceAttribute() throws BadLocationException { } @Test - public void testCompletionDetailWithSource() throws BadLocationException { + public void testCompletionDocumentationWithSource() throws BadLocationException { // completion on <| String xml = "\r\n" + // " \r\n" + // "\r\n" + // " <|"; - testCompletionFor(xml, c("catalog", te(5, 2, 5, 3, "$1$0"), "$1$0"), "\r\n" + // "\r\n" + // @@ -422,6 +431,37 @@ public void issue214() throws BadLocationException { c("ComplexType", "")); } + @Test + public void issue214WithMarkdown() throws BadLocationException, MalformedURIException { + String edmxURI = getXMLSchemaFileURI("edmx.xsd"); + String edmURI = getXMLSchemaFileURI("edm.xsd"); + String xml = "\r\n" + // + "\r\n" + + // + " \r\n" + + // + " \r\n" + // + " \r\n" + // + " \r\n" + // + " |"; + testCompletionMarkdownSupporytFor(xml, + c("Annotation", te(6, 1, 6, 1, ""), "Annotation", + "Source: [edm.xsd](" + edmURI + ")", MarkupKind.MARKDOWN), // + c("edmx:Include", te(6, 1, 6, 1, ""), "edmx:Include", + "Source: [edmx.xsd](" + edmxURI + ")", MarkupKind.MARKDOWN), // + c("edmx:IncludeAnnotations", "")); + + xml = "\r\n" + + " \r\n" + + " \r\n" + // + " \r\n" + // + " |"; + testCompletionMarkdownSupporytFor(xml, c("Action", ""), // + c("Annotation", ""), // + c("Annotations", ""), // + c("ComplexType", "")); + } + /** * @see https://github.com/angelozerr/lsp4xml/issues/311 * @@ -782,7 +822,60 @@ public void tag() throws BadLocationException { } + @Test + public void documentationAsPlainText() throws BadLocationException { + String xml = "\r\n" + + // + " <|" + // + ""; + testCompletionFor(xml, c("groupId", te(3, 1, 3, 2, ""), "org.apache.maven)." + // + System.lineSeparator() + // + System.lineSeparator() + // + "Source: maven-4.0.0.xsd", + MarkupKind.PLAINTEXT)); + + } + + @Test + public void documentationAsMarkdown() throws BadLocationException, MalformedURIException { + String xml = "\r\n" + + // + " <|" + // + ""; + + String mavenFileURI = getXMLSchemaFileURI("maven-4.0.0.xsd"); + testCompletionMarkdownSupporytFor(xml, c("groupId", te(3, 1, 3, 2, ""), "\r\n" + // "\r\n" + " "; assertHover(xml, - "Defines a single (usually named) bean. A bean definition may contain nested tags for constructor arguments, property values, lookup methods, and replaced methods. Mixing constructor injection and setter injection on the same bean is explicitly supported.", + "Defines a single (usually named) bean. A bean definition may contain nested tags for constructor arguments, property values, lookup methods, and replaced methods. Mixing constructor injection and setter injection on the same bean is explicitly supported." + + // + System.lineSeparator() + // + System.lineSeparator() + "Source: [spring-beans-3.0.xsd](" + schemaURI + ")", 2); }; @Test - public void testAttributeNameHover() throws BadLocationException { + public void testAttributeNameHover() throws BadLocationException, MalformedURIException { + String schemaURI = getXMLSchemaFileURI("spring-beans-3.0.xsd"); String xml = "\r\n" + // "\r\n" + " "; assertHover(xml, - "The fully qualified name of the bean's class, except if it serves only as a parent definition for child bean definitions.", + "The fully qualified name of the bean's class, except if it serves only as a parent definition for child bean definitions." + + // + System.lineSeparator() + // + System.lineSeparator() + "Source: [spring-beans-3.0.xsd](" + schemaURI + ")", null); }; @Test - public void testTagHoverFromXSType() throws BadLocationException { + public void testTagHoverFromXSType() throws BadLocationException, MalformedURIException { + String schemaURI = getXMLSchemaFileURI("invoice.xsd"); // web.xml servlet, servlet-name declares their xs:annotation not in the element // declaration but in type (servletType), // this test checks that String xml = "\r\n" + // - "\r\n"; + "\r\n"; XMLAssert.assertHover(new XMLLanguageService(), xml, null, "src/test/resources/invoice.xml", - "An invoice type...", null); + "An invoice type..." + // + System.lineSeparator() + // + System.lineSeparator() + "Source: [invoice.xsd](" + schemaURI + ")", + null); }; @Test public void testTagHoverForSchemaLocation() throws BadLocationException { String xml = "\r\n" + // - "\r\n"; - + "\r\n"; XMLAssert.assertHover(new XMLLanguageService(), xml, null, "src/test/resources/invoice.xml", XSISchemaModel.SCHEMA_LOCATION_DOC, null); }; @@ -67,9 +80,8 @@ public void testTagHoverForSchemaLocation() throws BadLocationException { @Test public void testTagHoverForNoNamespaceSchemaLocation() throws BadLocationException { String xml = "\r\n" + // - "\r\n"; - + "\r\n"; XMLAssert.assertHover(new XMLLanguageService(), xml, null, "src/test/resources/invoice.xml", XSISchemaModel.NO_NAMESPACE_SCHEMA_LOCATION_DOC, null); }; @@ -77,9 +89,8 @@ public void testTagHoverForNoNamespaceSchemaLocation() throws BadLocationExcepti @Test public void testTagHoverForXSInil() throws BadLocationException { String xml = "\r\n" + // - "\r\n"; - + "\r\n"; XMLAssert.assertHover(new XMLLanguageService(), xml, null, "src/test/resources/invoice.xml", XSISchemaModel.NIL_DOC, null); }; @@ -87,9 +98,8 @@ public void testTagHoverForXSInil() throws BadLocationException { @Test public void testTagHoverForXSIType() throws BadLocationException { String xml = "\r\n" + // - "\r\n"; - + "\r\n"; XMLAssert.assertHover(new XMLLanguageService(), xml, null, "src/test/resources/invoice.xml", XSISchemaModel.TYPE_DOC, null); }; @@ -97,9 +107,8 @@ public void testTagHoverForXSIType() throws BadLocationException { @Test public void testTagHoverForXSIType2() throws BadLocationException { String xml = "\r\n" + // - "\r\n"; - + "\r\n"; XMLAssert.assertHover(new XMLLanguageService(), xml, null, "src/test/resources/invoice.xml", XSISchemaModel.TYPE_DOC, null); }; @@ -107,20 +116,17 @@ public void testTagHoverForXSIType2() throws BadLocationException { @Test public void testTagHoverForXSIBadPrefix() throws BadLocationException { String xml = "\r\n" + // - "\r\n"; - - XMLAssert.assertHover(new XMLLanguageService(), xml, null, "src/test/resources/invoice.xml", - null, null); + "\r\n"; + XMLAssert.assertHover(new XMLLanguageService(), xml, null, "src/test/resources/invoice.xml", null, null); }; @Test public void testTagHoverForXSITypeNotRoot() throws BadLocationException { String xml = "\r\n" + // - "\r\n" + + "\r\n" + // ""; - XMLAssert.assertHover(new XMLLanguageService(), xml, null, "src/test/resources/invoice.xml", XSISchemaModel.TYPE_DOC, null); }; @@ -128,10 +134,10 @@ public void testTagHoverForXSITypeNotRoot() throws BadLocationException { @Test public void testTagHoverForXSINILNotRoot() throws BadLocationException { String xml = "\r\n" + // - "\r\n" + + "\r\n" + // ""; - + XMLAssert.assertHover(new XMLLanguageService(), xml, null, "src/test/resources/invoice.xml", XSISchemaModel.NIL_DOC, null); }; @@ -139,46 +145,49 @@ public void testTagHoverForXSINILNotRoot() throws BadLocationException { @Test public void testTagHoverForXSISchemaNotRoot() throws BadLocationException { String xml = "\r\n" + // - "\r\n" + + "\r\n" + // ""; - - XMLAssert.assertHover(new XMLLanguageService(), xml, null, "src/test/resources/invoice.xml", - null, null); + + XMLAssert.assertHover(new XMLLanguageService(), xml, null, "src/test/resources/invoice.xml", null, null); }; @Test - public void testHoverAttributeValueEuro() throws BadLocationException { - String xml = - "\r\n" + - ""; - XMLAssert.assertHover(new XMLLanguageService(), xml, null, "src/test/resources/money.xml", - "Euro Hover", null); + public void testHoverAttributeValueEuro() throws BadLocationException, MalformedURIException { + String schemaURI = getXMLSchemaFileURI("money.xsd"); + String xml = "\r\n" + // + ""; + XMLAssert.assertHover(new XMLLanguageService(), xml, null, "src/test/resources/money.xml", "Euro Hover" + // + System.lineSeparator() + // + System.lineSeparator() + "Source: [money.xsd](" + schemaURI + ")", null); }; @Test - public void testHoverAttributeValuePound() throws BadLocationException { - String xml = - "\r\n" + - ""; - XMLAssert.assertHover(new XMLLanguageService(), xml, null, "src/test/resources/money.xml", - "Pound Hover", null); + public void testHoverAttributeValuePound() throws BadLocationException, MalformedURIException { + String schemaURI = getXMLSchemaFileURI("money.xsd"); + String xml = "\r\n" + // + ""; + XMLAssert.assertHover(new XMLLanguageService(), xml, null, "src/test/resources/money.xml", "Pound Hover" + // + System.lineSeparator() + // + System.lineSeparator() + "Source: [money.xsd](" + schemaURI + ")", null); }; - @Test - public void testHoverAttributeValueNonExistent() throws BadLocationException { - String xml = - "\r\n" + - ""; + public void testHoverAttributeValueNonExistent() throws BadLocationException, MalformedURIException { + String schemaURI = getXMLSchemaFileURI("money.xsd"); + String xml = "\r\n" + // + ""; XMLAssert.assertHover(new XMLLanguageService(), xml, null, "src/test/resources/money.xml", - "Currency name Hover", null); + "Currency name Hover" + // + System.lineSeparator() + // + System.lineSeparator() + "Source: [money.xsd](" + schemaURI + ")", + null); }; private static void assertHover(String value, String expectedHoverLabel, Integer expectedHoverOffset) @@ -187,4 +196,8 @@ private static void assertHover(String value, String expectedHoverLabel, Integer expectedHoverLabel, expectedHoverOffset); } + private static String getXMLSchemaFileURI(String schemaURI) throws MalformedURIException { + return XMLEntityManager.expandSystemId("xsd/" + schemaURI, "src/test/resources/test.xml", true).replace("///", + "/"); + } } diff --git a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/xsd/XSDCompletionExtensionsTest.java b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/xsd/XSDCompletionExtensionsTest.java index e03a6eaf0..d702ae0a9 100644 --- a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/xsd/XSDCompletionExtensionsTest.java +++ b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/xsd/XSDCompletionExtensionsTest.java @@ -14,6 +14,7 @@ import static org.eclipse.lsp4xml.XMLAssert.te; import org.eclipse.lsp4j.CompletionItem; +import org.eclipse.lsp4j.MarkupKind; import org.eclipse.lsp4xml.XMLAssert; import org.eclipse.lsp4xml.commons.BadLocationException; import org.junit.Test; @@ -36,7 +37,7 @@ public void completion() throws BadLocationException { } @Test - public void completionWithSourceDetail() throws BadLocationException { + public void completionWithSourceDocumentation() throws BadLocationException { // completion on | String xml = "\r\n" + " \r\n" @@ -44,13 +45,13 @@ public void completionWithSourceDetail() throws BadLocationException { "|"; testCompletionFor(xml, c("xs:annotation", te(2, 0, 2, 0, ""), "xs:annotation", - "Source: XMLSchema.xsd"), + "Source: XMLSchema.xsd", MarkupKind.PLAINTEXT), c("xs:attribute", te(2, 0, 2, 0, ""), "xs:attribute", - "Source: XMLSchema.xsd")); + "Source: XMLSchema.xsd", MarkupKind.PLAINTEXT)); } @Test - public void completionWithSourceDescriptionAndDetail() throws BadLocationException { + public void completionWithSourceDescriptionAndDocumentation() throws BadLocationException { String xml = "\r\n" + // "\r\n" + // @@ -58,7 +59,7 @@ public void completionWithSourceDescriptionAndDetail() throws BadLocationExcepti String lineSeparator = System.getProperty("line.separator"); XMLAssert.testCompletionFor(xml, null, "src/test/resources/invoice.xml", null, c("date", te(3, 2, 3, 3, ""), "