Skip to content

Commit

Permalink
Indication in description of completion item that includes
Browse files Browse the repository at this point in the history
the file name of the schema they come from.

Fixes eclipse-lemminx#210

Signed-off-by: Nikolas Komonen <[email protected]>
  • Loading branch information
NikolasKomonen committed May 27, 2019
1 parent 12e3956 commit 214a197
Show file tree
Hide file tree
Showing 10 changed files with 129 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,6 @@ public interface CMDocument {
*/
CMElementDeclaration findCMElement(DOMElement element, String namespace);

String getURI();

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
*/
package org.eclipse.lsp4xml.extensions.contentmodel.participants;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collection;

import org.eclipse.lsp4j.CompletionItem;
Expand All @@ -31,6 +33,7 @@
import org.eclipse.lsp4xml.services.extensions.ICompletionResponse;
import org.eclipse.lsp4xml.settings.SharedSettings;
import org.eclipse.lsp4xml.uriresolver.CacheResourceDownloadingException;
import org.eclipse.lsp4xml.utils.StringUtils;

/**
* Extension to support XML completion based on content model (XML Schema
Expand All @@ -42,26 +45,34 @@ public class ContentModelCompletionParticipant extends CompletionParticipantAdap
public void onTagOpen(ICompletionRequest request, ICompletionResponse response) throws Exception {
try {
DOMDocument document = request.getXMLDocument();
String schemaURI;
String fileURI;
ContentModelManager contentModelManager = request.getComponent(ContentModelManager.class);
DOMElement parentElement = request.getParentElement();
CMDocument cmDocument;
if (parentElement == null) {
// XML is empty, in case of XML file associations, a XMl Schema/DTD can be bound
// check if it's root element (in the case of XML file associations, the link to
// XML Schema is done with pattern and not with XML root element)
CMDocument cmDocument = contentModelManager.findCMDocument(document, null);
cmDocument = contentModelManager.findCMDocument(document, null);
if (cmDocument != null) {
fillWithChildrenElementDeclaration(null, cmDocument.getElements(), null, false, request, response);
schemaURI = cmDocument.getURI();
fillWithChildrenElementDeclaration(null, cmDocument.getElements(), null, false, request, response, schemaURI);
}
return;
}
// Try to retrieve XML Schema/DTD element declaration for the parent element
// where completion was triggered.
cmDocument = contentModelManager.findCMDocument(parentElement, parentElement.getNamespaceURI());

schemaURI = cmDocument != null ? cmDocument.getURI() : null;
CMElementDeclaration cmElement = contentModelManager.findCMElement(parentElement);
String defaultPrefix = null;

if (cmElement != null) {
defaultPrefix = parentElement.getPrefix();
fillWithChildrenElementDeclaration(parentElement, cmElement.getElements(), defaultPrefix, false,
request, response);
request, response, schemaURI);
}
if (parentElement.isDocumentElement()) {
// root document element
Expand All @@ -71,10 +82,10 @@ public void onTagOpen(ICompletionRequest request, ICompletionResponse response)
continue;
}
String namespaceURI = parentElement.getNamespaceURI(prefix);
CMDocument cmDocument = contentModelManager.findCMDocument(parentElement, namespaceURI);
cmDocument = contentModelManager.findCMDocument(parentElement, namespaceURI);
if (cmDocument != null) {
fillWithChildrenElementDeclaration(parentElement, cmDocument.getElements(), prefix, true,
request, response);
request, response, cmDocument.getURI());
}
}
}
Expand All @@ -84,15 +95,15 @@ public void onTagOpen(ICompletionRequest request, ICompletionResponse response)
if (cmInternalElement != null) {
defaultPrefix = parentElement.getPrefix();
fillWithChildrenElementDeclaration(parentElement, cmInternalElement.getElements(), defaultPrefix, false,
request, response);
request, response, schemaURI);
}
} catch (CacheResourceDownloadingException e) {
// XML Schema, DTD is loading, ignore this error
}
}

private void fillWithChildrenElementDeclaration(DOMElement element, Collection<CMElementDeclaration> cmElements,
String p, boolean forceUseOfPrefix, ICompletionRequest request, ICompletionResponse response)
String p, boolean forceUseOfPrefix, ICompletionRequest request, ICompletionResponse response, String schemaURI)
throws BadLocationException {
XMLGenerator generator = request.getXMLGenerator();
for (CMElementDeclaration child : cmElements) {
Expand All @@ -101,8 +112,26 @@ private void fillWithChildrenElementDeclaration(DOMElement element, Collection<C
CompletionItem item = new CompletionItem(label);
item.setFilterText(request.getFilterForStartTagName(label));
item.setKind(CompletionItemKind.Property);
String documentation = child.getDocumentation();
if (documentation != null) {
StringBuilder sb = new StringBuilder();
String documentation;
String tempDoc = child.getDocumentation();
boolean tempDocHasContent = !StringUtils.isEmpty(tempDoc);
if(tempDocHasContent) {
sb.append(tempDoc);
}

if(schemaURI != null) {
if(tempDocHasContent) {
String lineSeparator = System.getProperty("line.separator");
sb.append(lineSeparator);
sb.append(lineSeparator);
}
Path schemaPath = Paths.get(schemaURI);
sb.append("Source: ");
sb.append(schemaPath.getFileName().toString());
}
documentation = sb.toString();
if (documentation != null && !documentation.isEmpty()) {
item.setDetail(documentation);
}
String xml = generator.generate(child, prefix);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public String getSystemId(DOMDocument xmlDocument, String namespaceURI) {
@Override
public CMDocument createCMDocument(String key) {
try {
CMDTDDocument document = new CMDTDDocument();
CMDTDDocument document = new CMDTDDocument(key);
document.setEntityResolver(resolverExtensionManager);
Grammar grammar = document.loadGrammar(new XMLInputSource(null, key, null));
if (grammar != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ public class CMDTDDocument extends XMLDTDLoader implements CMDocument {
private List<CMElementDeclaration> elements;
private DTDGrammar grammar;
private List<String> hierachies;
private String uri;


public CMDTDDocument() {

}

public CMDTDDocument(String uri) {
this.uri = uri;
}

@Override
public Collection<CMElementDeclaration> getElements() {
Expand All @@ -58,6 +68,15 @@ public Collection<CMElementDeclaration> getElements() {
return elements;
}

@Override
/**
* Returns the URI of this document, is none was provided this
* returns null.
*/
public String getURI() {
return uri;
}

@Override
public CMElementDeclaration findCMElement(DOMElement element, String namespace) {
List<DOMElement> paths = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ public CMDocument createCMDocument(String key) {
XSModel model = getLoader().loadURI(key);
if (model != null) {
// XML Schema can be loaded
return new CMXSDDocument(model);
CMXSDDocument document = new CMXSDDocument(model, key);
return document;
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,24 @@ public class CMXSDDocument implements CMDocument {

private Collection<CMElementDeclaration> elements;

private String uri;

public CMXSDDocument(XSModel model) {
this.model = model;
this.elementMappings = new HashMap<>();
}

public CMXSDDocument(XSModel model, String uri) {
this.model = model;
this.elementMappings = new HashMap<>();
this.uri = uri;
}

@Override
public String getURI() {
return uri;
}

@Override
public Collection<CMElementDeclaration> getElements() {
if (elements == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,19 @@ private static void assertCompletion(CompletionList completions, CompletionItem
Assert.assertEquals(expected.getFilterText(), match.getFilterText());
}

if(expected.getDetail() != null) {
Assert.assertEquals(expected.getDetail(), match.getDetail());
}

}

public static CompletionItem c(String label, TextEdit textEdit, String filterText, String detail) {
CompletionItem item = new CompletionItem();
item.setLabel(label);
item.setFilterText(filterText);
item.setTextEdit(textEdit);
item.setDetail(detail);
return item;
}

public static CompletionItem c(String label, TextEdit textEdit, String filterText) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@ public void completionWithChoiceAttribute() throws BadLocationException {
testCompletionFor(xml, c("prefer", te(5, 11, 5, 11, "prefer=\"${1|system,public|}\"$0"), "prefer"));
}

@Test
public void testCompletionDetailWithSource() throws BadLocationException {
// completion on <|
String xml = "<?xml version=\"1.0\"?>\r\n" + //
" <!DOCTYPE catalog\r\n" + //
" PUBLIC \"-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN\"\r\n" + //
" \"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, "<catalog>$1</catalog>$0"), "<catalog", "Source: catalog.dtd"));
}

@Test
public void externalDTDCompletionElement() throws BadLocationException {
// completion on <|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,28 @@ public void completion() throws BadLocationException {
c("xs:attribute", te(2, 0, 2, 0, "<xs:attribute name=\"\"></xs:attribute>"), "xs:attribute"));
}

@Test
public void completionWithSourceDetail() throws BadLocationException {
// completion on |
String xml = "<?xml version=\"1.1\"?>\r\n"
+ "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" elementFormDefault=\"qualified\" attributeFormDefault=\"unqualified\"> \r\n"
+ //
"|";
testCompletionFor(xml, c("xs:annotation", te(2, 0, 2, 0, "<xs:annotation></xs:annotation>"), "xs:annotation", "Source: XMLSchema.xsd"),
c("xs:attribute", te(2, 0, 2, 0, "<xs:attribute name=\"\"></xs:attribute>"), "xs:attribute", "Source: XMLSchema.xsd"));
}

@Test
public void completionWithSourceDescriptionAndDetail() throws BadLocationException {
String xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" + //
"<invoice xmlns=\"http://invoice\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\r\n"
+ " xsi:schemaLocation=\"http://invoice xsd/invoice.xsd \">\r\n" + //
" <|";
String lineSeparator = System.getProperty("line.separator");
XMLAssert.testCompletionFor(xml, null, "src/test/resources/invoice.xml", null, c("date", te(3, 2, 3, 3, "<date></date>"), "<date", "Date Description" + lineSeparator + lineSeparator + "Source: invoice.xsd"),
c("number", "<number></number>"));
}

private void testCompletionFor(String xml, CompletionItem... expectedItems) throws BadLocationException {
XMLAssert.testCompletionFor(xml, null, expectedItems);
}
Expand Down
10 changes: 7 additions & 3 deletions org.eclipse.lsp4xml/src/test/resources/xsd/invoice.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@
<xsd:documentation>An invoice type...</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="date" type="xsd:date" nillable="true"></xsd:element>
<xsd:element name="number" type="xsd:int"></xsd:element>
<xsd:element name="products" type="productsType"></xsd:element>
<xsd:element name="date" type="xsd:date" nillable="true">
<xsd:annotation>
<xsd:documentation>Date Description</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="number" type="xsd:int"></xsd:element>
<xsd:element name="products" type="productsType"></xsd:element>
<xsd:element name="payments" type="paymentsType"></xsd:element>
</xsd:sequence>
</xsd:complexType>
Expand Down

0 comments on commit 214a197

Please sign in to comment.