From 9286aa047f3d49ebcc0ecbe9d389920fc702c7de Mon Sep 17 00:00:00 2001 From: Seiphon <871358932@qq.com> Date: Wed, 6 Nov 2019 13:19:35 +0800 Subject: [PATCH] DTD hover/completion support for documentation Fixes #585 Signed-off-by: Seiphon Wang --- .../CMDTDAttributeDeclaration.java | 13 +- .../dtd/contentmodel/CMDTDDocument.java | 103 ++- .../contentmodel/CMDTDElementDeclaration.java | 27 +- .../DTDCompletionExtensionsTest.java | 5 +- .../contentmodel/DTDHoverExtensionsTest.java | 64 ++ .../resources/catalogs/catalog-liferay.xml | 6 + .../dtd/liferay-service-builder_7_2_0.dtd | 845 ++++++++++++++++++ 7 files changed, 1055 insertions(+), 8 deletions(-) create mode 100644 org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/contentmodel/DTDHoverExtensionsTest.java create mode 100644 org.eclipse.lsp4xml/src/test/resources/catalogs/catalog-liferay.xml create mode 100644 org.eclipse.lsp4xml/src/test/resources/dtd/liferay-service-builder_7_2_0.dtd diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/dtd/contentmodel/CMDTDAttributeDeclaration.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/dtd/contentmodel/CMDTDAttributeDeclaration.java index ae4e5fc69..7004b99b1 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/dtd/contentmodel/CMDTDAttributeDeclaration.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/dtd/contentmodel/CMDTDAttributeDeclaration.java @@ -24,6 +24,13 @@ */ public class CMDTDAttributeDeclaration extends XMLAttributeDecl implements CMAttributeDeclaration { + private String documentation; + private CMDTDElementDeclaration elementDecl; + + public CMDTDAttributeDeclaration(CMDTDElementDeclaration elementDecl) { + this.elementDecl = elementDecl; + } + @Override public String getName() { return super.name.localpart; @@ -45,7 +52,11 @@ public Collection getEnumerationValues() { @Override public String getDocumentation() { - return null; + if (documentation != null) { + return documentation; + } + documentation = elementDecl.getDocumentation(getName()); + return documentation; } @Override diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/dtd/contentmodel/CMDTDDocument.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/dtd/contentmodel/CMDTDDocument.java index 2acb45e14..a53d690d9 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/dtd/contentmodel/CMDTDDocument.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/dtd/contentmodel/CMDTDDocument.java @@ -23,6 +23,7 @@ import org.apache.xerces.impl.dtd.DTDGrammar; import org.apache.xerces.impl.dtd.XMLDTDLoader; import org.apache.xerces.xni.Augmentations; +import org.apache.xerces.xni.XMLString; import org.apache.xerces.xni.XNIException; import org.apache.xerces.xni.grammars.Grammar; import org.apache.xerces.xni.parser.XMLInputSource; @@ -43,13 +44,59 @@ */ public class CMDTDDocument extends XMLDTDLoader implements CMDocument { + + static class DTDNodeInfo { + + private String comment; + + public DTDNodeInfo() { + this.comment = null; + } + + public String getComment() { + return comment; + } + + public void setComment(String comment) { + this.comment = comment; + } + } + + static class DTDElementInfo extends DTDNodeInfo { + + private final Set hierarchies; + private final Map attributes; + + public DTDElementInfo() { + this.hierarchies = new LinkedHashSet(); + this.attributes = new HashMap<>(); + } + + public Set getHierarchies() { + return hierarchies; + } + + public Map getAttributes() { + return attributes; + } + + public String getComment(String attrName) { + DTDNodeInfo attr = attributes.get(attrName); + return attr != null ? attr.getComment() : null; + } + } + private final String uri; - private Map> hierarchiesMap; + private Map hierarchiesMap; private List elements; private DTDGrammar grammar; private Set hierarchies; private FilesChangedTracker tracker; + private String comment; + private DTDElementInfo dtdElementInfo; + private Map attributes; + private DTDNodeInfo nodeInfo; public CMDTDDocument() { this(null); @@ -124,23 +171,55 @@ public void startContentModel(String elementName, Augmentations augs) throws XNI if (hierarchiesMap == null) { hierarchiesMap = new HashMap<>(); } - hierarchies = new LinkedHashSet(); - hierarchiesMap.put(elementName, hierarchies); + dtdElementInfo = new DTDElementInfo(); + if (comment != null) { + dtdElementInfo.setComment(comment); + } + hierarchiesMap.put(elementName, dtdElementInfo); super.startContentModel(elementName, augs); } @Override public void element(String elementName, Augmentations augs) throws XNIException { + hierarchies = dtdElementInfo.getHierarchies(); hierarchies.add(elementName); super.element(elementName, augs); } @Override public void endContentModel(Augmentations augs) throws XNIException { + comment = null; hierarchies = null; super.endContentModel(augs); } + @Override + public void startAttlist(String elementName, Augmentations augs) throws XNIException { + attributes = dtdElementInfo.getAttributes(); + super.startAttlist(elementName, augs); + } + + @Override + public void attributeDecl(String elementName, String attributeName, String type, String[] enumeration, + String defaultType, XMLString defaultValue, XMLString nonNormalizedDefaultValue, Augmentations augs) + throws XNIException { + if (comment != null) { + nodeInfo = new DTDNodeInfo(); + nodeInfo.setComment(comment); + attributes.put(attributeName, nodeInfo); + } + super.attributeDecl(elementName, attributeName, type, enumeration, defaultType, defaultValue, nonNormalizedDefaultValue, + augs); + } + + @Override + public void endAttlist(Augmentations augs) throws XNIException { + comment = null; + attributes = null; + nodeInfo = null; + super.endAttlist(augs); + } + @Override public Grammar loadGrammar(XMLInputSource source) throws IOException, XNIException { grammar = (DTDGrammar) super.loadGrammar(source); @@ -164,11 +243,24 @@ public void loadInternalDTD(String internalSubset, String baseSystemId, String s fDTDScanner.scanDTDInternalSubset(true, false, systemId != null); } + @Override + public void comment(XMLString text, Augmentations augs) throws XNIException { + if (text != null) { + comment = text.toString(); + } + super.comment(text, augs); + } + + public Map getHierarchiesMap() { + return hierarchiesMap; + } + void collectElementsDeclaration(String elementName, List elements) { if (hierarchiesMap == null) { return; } - Set children = hierarchiesMap.get(elementName); + DTDElementInfo elementInfo = hierarchiesMap.get(elementName); + Set children = elementInfo.getHierarchies(); if (children == null) { return; } @@ -184,7 +276,7 @@ void collectAttributesDeclaration(CMDTDElementDeclaration elementDecl, List elements; private List attributes; + private String documentation; public CMDTDElementDeclaration(CMDTDDocument document, int index) { this.document = document; @@ -91,7 +95,28 @@ public CMAttributeDeclaration findCMAttribute(String attributeName) { @Override public String getDocumentation() { - return null; + if (documentation != null) { + return documentation; + } + Map hierarchiesMap = document.getHierarchiesMap(); + if (hierarchiesMap != null) { + DTDElementInfo dtdElementInfo = hierarchiesMap.get(getName()); + documentation = dtdElementInfo.getComment(); + } + return documentation; + } + + public String getDocumentation(String attrName) { + Map hierarchiesMap = document.getHierarchiesMap(); + if (hierarchiesMap != null) { + DTDElementInfo dtdElementInfo = hierarchiesMap.get(getName()); + Map attributesMap = dtdElementInfo.getAttributes(); + DTDNodeInfo nodeInfo = attributesMap.get(attrName); + if (nodeInfo != null) { + documentation = nodeInfo.getComment(); + } + } + return documentation; } @Override 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 290c8239b..480fae0e0 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 @@ -54,7 +54,10 @@ public void testCompletionDocumentationWithSource() throws BadLocationException " \"http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd\">\r\n" + // "\r\n" + // " <|"; - testCompletionFor(xml, c("catalog", te(5, 2, 5, 3, "$1$0"), "$1$0"), " - initial API and implementation + * Seiphon Wang + */ +package org.eclipse.lsp4xml.extensions.contentmodel; + +import org.apache.xerces.impl.XMLEntityManager; +import org.apache.xerces.util.URI.MalformedURIException; +import org.eclipse.lsp4xml.XMLAssert; +import org.eclipse.lsp4xml.commons.BadLocationException; +import org.eclipse.lsp4xml.services.XMLLanguageService; +import org.junit.Test; + +public class DTDHoverExtensionsTest { + + @Test + public void testTagHover() throws BadLocationException, MalformedURIException { + String dtdURI = getDTDFileURI("liferay-service-builder_7_2_0.dtd"); + String xml = "\r\n" + // + "" + + ""; + assertHover(xml,"The service-builder element is the root of the deployment descriptor for" + // + " a Service Builder descriptor that is used to generate services available to" + + " portlets. The Service Builder saves the developer time by generating Spring" + + " utilities, SOAP utilities, and Hibernate persistence classes to ease the" + + " development of services." + + // + System.lineSeparator() + // + System.lineSeparator() + "Source: [liferay-service-builder_7_2_0.dtd](" + dtdURI + ")", + 206); + } + + @Test + public void testAttributeNameHover() throws BadLocationException, MalformedURIException { + String dtdURI = getDTDFileURI("liferay-service-builder_7_2_0.dtd"); + String xml = "\r\n" + // + "" + + ""; + assertHover(xml, + "The package-path value specifies the package of the generated code." + + // + System.lineSeparator() + // + System.lineSeparator() + "Source: [liferay-service-builder_7_2_0.dtd](" + dtdURI + ")", + null); + } + + private static void assertHover(String value, String expectedHoverLabel, Integer expectedHoverOffset) + throws BadLocationException { + XMLAssert.assertHover(new XMLLanguageService(), value, "src/test/resources/catalogs/catalog-liferay.xml", null, + expectedHoverLabel, expectedHoverOffset); + } + + private static String getDTDFileURI(String dtdURI) throws MalformedURIException { + return XMLEntityManager.expandSystemId("dtd/" + dtdURI, "src/test/resources/test.xml", true).replace("///", + "/"); + } +} diff --git a/org.eclipse.lsp4xml/src/test/resources/catalogs/catalog-liferay.xml b/org.eclipse.lsp4xml/src/test/resources/catalogs/catalog-liferay.xml new file mode 100644 index 000000000..849c999f7 --- /dev/null +++ b/org.eclipse.lsp4xml/src/test/resources/catalogs/catalog-liferay.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/org.eclipse.lsp4xml/src/test/resources/dtd/liferay-service-builder_7_2_0.dtd b/org.eclipse.lsp4xml/src/test/resources/dtd/liferay-service-builder_7_2_0.dtd new file mode 100644 index 000000000..6e0e72b9d --- /dev/null +++ b/org.eclipse.lsp4xml/src/test/resources/dtd/liferay-service-builder_7_2_0.dtd @@ -0,0 +1,845 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file