From b2c2a08ebc7296e2008dc2c9367491b558200809 Mon Sep 17 00:00:00 2001 From: Nikolas Komonen Date: Wed, 19 Dec 2018 15:21:03 -0500 Subject: [PATCH] DTD Formatting implemented Fixes #221 and #268 Signed-off-by: Nikolas Komonen --- org.eclipse.lsp4xml/delete.dtd | 2 + org.eclipse.lsp4xml/delete.xml | 1 + .../org/eclipse/lsp4xml/dom/DOMDocument.java | 2 +- .../eclipse/lsp4xml/dom/DOMDocumentType.java | 106 ++- .../java/org/eclipse/lsp4xml/dom/DOMNode.java | 7 + .../org/eclipse/lsp4xml/dom/DOMParser.java | 96 ++- .../eclipse/lsp4xml/dom/DTDAttlistDecl.java | 44 +- .../org/eclipse/lsp4xml/dom/DTDDeclNode.java | 60 +- .../eclipse/lsp4xml/dom/DTDDeclParameter.java | 71 ++ .../eclipse/lsp4xml/dom/DTDElementDecl.java | 33 +- .../eclipse/lsp4xml/dom/DTDEntityDecl.java | 65 +- .../eclipse/lsp4xml/dom/DTDNotationDecl.java | 38 +- .../dom/DTDUnrecognizedDeclParameter.java | 15 + .../eclipse/lsp4xml/dom/LineIndentInfo.java | 12 + .../eclipse/lsp4xml/dom/parser/Constants.java | 4 +- .../lsp4xml/dom/parser/MultiLineStream.java | 72 ++ .../lsp4xml/dom/parser/ScannerState.java | 2 +- .../lsp4xml/dom/parser/XMLScanner.java | 66 +- .../participants/DTDErrorCode.java | 87 ++- .../CMDTDContentModelProvider.java | 2 +- .../lsp4xml/services/XMLFormatter.java | 245 +++++-- .../org/eclipse/lsp4xml/utils/XMLBuilder.java | 38 +- .../lsp4xml/utils/XMLPositionUtility.java | 117 +++- .../dom/DOMParserForInternalDTDTest.java | 70 +- .../eclipse/lsp4xml/dom/DOMParserTest.java | 190 ++---- .../parser/XMLScannerForExternalDTDTest.java | 33 + .../contentmodel/DTDDiagnosticsTest.java | 2 +- .../DTDDoctypeDiagnosticsTest.java | 6 +- .../services/XMLDocumentSymbolsTest.java | 1 - .../lsp4xml/services/XMLFormatterTest.java | 613 +++++++++++++++++- 30 files changed, 1645 insertions(+), 455 deletions(-) create mode 100644 org.eclipse.lsp4xml/delete.dtd create mode 100644 org.eclipse.lsp4xml/delete.xml create mode 100644 org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDDeclParameter.java create mode 100644 org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDUnrecognizedDeclParameter.java diff --git a/org.eclipse.lsp4xml/delete.dtd b/org.eclipse.lsp4xml/delete.dtd new file mode 100644 index 0000000000..f013cd3c1e --- /dev/null +++ b/org.eclipse.lsp4xml/delete.dtd @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/org.eclipse.lsp4xml/delete.xml b/org.eclipse.lsp4xml/delete.xml new file mode 100644 index 0000000000..de62a5843f --- /dev/null +++ b/org.eclipse.lsp4xml/delete.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMDocument.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMDocument.java index f449eacb7e..8f858a8384 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMDocument.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMDocument.java @@ -770,7 +770,7 @@ public boolean isDTD() { */ public Collection findDTDAttrList(String elementName) { DOMDocumentType docType = getDoctype(); - if (docType == null) { + if (docType == null || elementName == null) { return Collections.emptyList(); } return docType.getChildren().stream().filter(DOMNode::isDTDAttListDecl) diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMDocumentType.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMDocumentType.java index 4a5789dd04..79855459fb 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMDocumentType.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMDocumentType.java @@ -16,27 +16,20 @@ * A doctype node. * */ -public class DOMDocumentType extends DOMNode implements org.w3c.dom.DocumentType { +public class DOMDocumentType extends DTDDeclNode implements org.w3c.dom.DocumentType { public enum DocumentTypeKind { PUBLIC, SYSTEM, INVALID } - - // Offset values relative to start of the XML Document - Integer nameStart, nameEnd; - Integer kindStart, kindEnd; - Integer publicIdStart, publicIdEnd; - Integer systemIdStart, systemIdEnd; - Integer internalSubsetStart, internalSubsetEnd; - - private String name; - private String kind; // SYSTEM || PUBLIC - private String publicId; - private String systemId; - private String internalSubset; + DTDDeclParameter name; + DTDDeclParameter kind; // SYSTEM || PUBLIC + DTDDeclParameter publicId; + DTDDeclParameter systemId; + DTDDeclParameter internalSubset; private String content; // || + //private String unrecognizedParameters; public DOMDocumentType(int start, int end, DOMDocument ownerDocument) { super(start, end, ownerDocument); @@ -49,43 +42,30 @@ public String getContent() { return content; } - void setEnd(int end) { - this.end = end; - this.content = getOwnerDocument().getText().substring(start, end); - } - /** * The text immediately after DOCTYPE, " children = getChildren(); int idx = findFirst(children, c -> offset <= c.start) - 1; @@ -394,6 +397,10 @@ public DOMElement getParentElement() { return null; } + public String getNodeAsString() { + return ownerDocument.getText().substring(start, end); + } + public boolean isComment() { return getNodeType() == DOMNode.COMMENT_NODE; } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMParser.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMParser.java index 359d33e5d2..c0b2c9e6ff 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMParser.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DOMParser.java @@ -45,6 +45,7 @@ public DOMDocument parse(String text, String uri, URIResolverExtensionManager re public DOMDocument parse(TextDocument document, URIResolverExtensionManager resolverExtensionManager) { boolean isDTD = DOMUtils.isDTD(document.getUri()); + boolean inDTDInternalSubset = false; String text = document.getText(); Scanner scanner = XMLScanner.createScanner(text, 0, isDTD); DOMDocument xmlDocument = new DOMDocument(document, resolverExtensionManager); @@ -73,11 +74,12 @@ public DOMDocument parse(TextDocument document, URIResolverExtensionManager reso curr.end = scanner.getTokenOffset(); } if((curr.isClosed()) || curr.isDoctype()) { - //The next node is being considered is a child of 'curr' + //The next node being considered is a child of 'curr' //and if 'curr' is already closed then 'curr' was not updated properly. //Or if we get a Doctype node then we know it was not closed and 'curr' //wasn't updated properly. curr = curr.parent; + inDTDInternalSubset = false; //In case it was previously in the internal subset } DOMElement child = xmlDocument.createElement(scanner.getTokenOffset(), scanner.getTokenEnd()); child.startTagOpenOffset = scanner.getTokenOffset(); @@ -170,7 +172,11 @@ public DOMDocument parse(TextDocument document, URIResolverExtensionManager reso if(lastClosed.isElement()) { ((DOMElement) curr).endTagCloseOffset = scanner.getTokenOffset(); } + if(curr.isDoctype()) { + curr.closed = true; + } curr = curr.parent; + } break; @@ -254,8 +260,10 @@ public DOMDocument parse(TextDocument document, URIResolverExtensionManager reso } case StartCommentTag: { - if(xmlDocument.isDTD()) { - if(!curr.isDoctype()) { + //Incase the tag before the comment tag (curr) was not properly closed + //curr should be set to the root node. + if(xmlDocument.isDTD() || inDTDInternalSubset) { + while(!curr.isDoctype()) { curr = curr.parent; } } @@ -263,9 +271,6 @@ else if((curr.isClosed())) { curr = curr.parent; } DOMComment comment = xmlDocument.createComment(scanner.getTokenOffset(), text.length()); - if(curr.parent != null && curr.parent.isDoctype()) { - curr.parent.addChild(comment); - } curr.addChild(comment); curr = comment; try { @@ -357,7 +362,8 @@ else if((curr.isClosed())) { case DTDStartInternalSubset: { DOMDocumentType doctype = (DOMDocumentType) curr; - doctype.internalSubsetStart = scanner.getTokenOffset(); + doctype.setStartInternalSubset(scanner.getTokenOffset()); + inDTDInternalSubset = true; break; } @@ -366,16 +372,16 @@ else if((curr.isClosed())) { curr.end = scanner.getTokenOffset() - 1; curr = curr.getParentNode(); } - + inDTDInternalSubset = false; DOMDocumentType doctype = (DOMDocumentType) curr; - doctype.internalSubsetEnd = scanner.getTokenEnd(); + doctype.setEndInternalSubset(scanner.getTokenEnd()); break; } case DTDStartElement: { - //If previous 'curr' was an unclosed ENTITY, ELEMENT, or ATTLIST + //If previous 'curr' was an unclosed DTD Declaration if (!curr.isDoctype()) { - curr.end = scanner.getTokenOffset() - 1; + curr.end = scanner.getTokenOffset(); curr = curr.getParentNode(); } @@ -388,38 +394,37 @@ else if((curr.isClosed())) { case DTDElementDeclName: { DTDElementDecl element = (DTDElementDecl) curr; - element.nameStart = scanner.getTokenOffset(); - element.nameEnd = scanner.getTokenEnd(); + element.setName(scanner.getTokenOffset(), scanner.getTokenEnd()); break; } case DTDElementCategory: { DTDElementDecl element = (DTDElementDecl) curr; - element.categoryStart = scanner.getTokenOffset(); - element.categoryEnd = scanner.getTokenEnd(); + element.setCategory(scanner.getTokenOffset(), scanner.getTokenEnd()); break; } case DTDStartElementContent: { DTDElementDecl element = (DTDElementDecl) curr; - element.contentStart = scanner.getTokenOffset(); + element.setContent(scanner.getTokenOffset(), scanner.getTokenEnd()); break; } case DTDElementContent: { DTDElementDecl element = (DTDElementDecl) curr; - element.contentEnd = scanner.getTokenEnd(); + element.updateLastParameterEnd(scanner.getTokenEnd()); + break; } case DTDEndElementContent: { DTDElementDecl element = (DTDElementDecl) curr; - element.contentEnd = scanner.getTokenEnd(); + element.updateLastParameterEnd(scanner.getTokenEnd()); break; } case DTDStartAttlist: { if (!curr.isDoctype()) { // If previous DTD Decl was unclosed - curr.end = scanner.getTokenOffset() - 1; + curr.end = scanner.getTokenOffset(); curr = curr.getParentNode(); } DTDAttlistDecl child = new DTDAttlistDecl(scanner.getTokenOffset(), text.length(), @@ -428,46 +433,39 @@ else if((curr.isClosed())) { isInitialDeclaration = true; curr.addChild(child); curr = child; - break; } case DTDAttlistElementName: { DTDAttlistDecl attribute = (DTDAttlistDecl) curr; - attribute.elementNameStart = scanner.getTokenOffset(); - attribute.elementNameEnd = scanner.getTokenEnd(); + attribute.setElementName(scanner.getTokenOffset(), scanner.getTokenEnd()); break; } - case DTDAttlistAttributeName: { DTDAttlistDecl attribute = (DTDAttlistDecl) curr; if(isInitialDeclaration == false) { // All additional declarations are created as new DTDAttlistDecl's - DTDAttlistDecl child = new DTDAttlistDecl(-1, -1, attribute.getParentDocumentType()); // Wont use these values + DTDAttlistDecl child = new DTDAttlistDecl(attribute.getStart(), attribute.getEnd(), attribute.getParentDocumentType()); attribute.addAdditionalAttDecl(child); child.parent = attribute; attribute = child; curr = child; } - - attribute.attributeNameStart = scanner.getTokenOffset(); - attribute.attributeNameEnd = scanner.getTokenEnd(); + attribute.setAttributeName(scanner.getTokenOffset(), scanner.getTokenEnd()); break; } case DTDAttlistAttributeType: { DTDAttlistDecl attribute = (DTDAttlistDecl) curr; - attribute.attributeTypeStart = scanner.getTokenOffset(); - attribute.attributeTypeEnd = scanner.getTokenEnd(); + attribute.setAttributeType(scanner.getTokenOffset(), scanner.getTokenEnd()); break; } case DTDAttlistAttributeValue: { DTDAttlistDecl attribute = (DTDAttlistDecl) curr; - attribute.attributeValueStart = scanner.getTokenOffset(); - attribute.attributeValueEnd = scanner.getTokenEnd(); + attribute.setAttributeValue(scanner.getTokenOffset(), scanner.getTokenEnd()); if(attribute.parent.isDTDAttListDecl()) { // Is not the root/main ATTLIST node curr = attribute.parent; @@ -477,11 +475,10 @@ else if((curr.isClosed())) { } break; } - - + case DTDStartEntity: { if (!curr.isDoctype()) { // If previous DTD Decl was unclosed - curr.end = scanner.getTokenOffset() - 1; + curr.end = scanner.getTokenOffset(); curr = curr.getParentNode(); } DTDEntityDecl child = new DTDEntityDecl(scanner.getTokenOffset(), text.length(), (DOMDocumentType) curr); @@ -492,52 +489,44 @@ else if((curr.isClosed())) { case DTDEntityPercent: { DTDEntityDecl entity = (DTDEntityDecl) curr; - entity.percentStart = scanner.getTokenOffset(); - entity.percentEnd = scanner.getTokenEnd(); + entity.setPercent(scanner.getTokenOffset(), scanner.getTokenEnd()); break; } case DTDEntityName : { DTDEntityDecl entity = (DTDEntityDecl) curr; - entity.nameStart = scanner.getTokenOffset(); - entity.nameEnd = scanner.getTokenEnd(); + entity.setNodeName(scanner.getTokenOffset(), scanner.getTokenEnd()); break; } case DTDEntityValue : { DTDEntityDecl entity = (DTDEntityDecl) curr; - entity.valueStart = scanner.getTokenOffset(); - entity.valueEnd = scanner.getTokenEnd(); + entity.setValue(scanner.getTokenOffset(), scanner.getTokenEnd()); break; } case DTDEntityKindPUBLIC: case DTDEntityKindSYSTEM: { DTDEntityDecl entity = (DTDEntityDecl) curr; - entity.kindStart = scanner.getTokenOffset(); - entity.kindEnd = scanner.getTokenEnd(); + entity.setKind(scanner.getTokenOffset(), scanner.getTokenEnd()); break; } case DTDEntityPublicId: { DTDEntityDecl entity = (DTDEntityDecl) curr; - entity.publicIdStart = scanner.getTokenOffset(); - entity.publicIdEnd = scanner.getTokenEnd(); + entity.setPublicId(scanner.getTokenOffset(), scanner.getTokenEnd()); break; } case DTDEntitySystemId: { DTDEntityDecl entity = (DTDEntityDecl) curr; - entity.systemIdStart = scanner.getTokenOffset(); - entity.systemIdEnd = scanner.getTokenEnd(); + entity.setSystemId(scanner.getTokenOffset(), scanner.getTokenEnd()); break; } - - case DTDStartNotation: { if (!curr.isDoctype()) { // If previous DTD Decl was unclosed - curr.end = scanner.getTokenOffset() - 1; + curr.end = scanner.getTokenOffset(); curr = curr.getParentNode(); } DTDNotationDecl child = new DTDNotationDecl(scanner.getTokenOffset(), text.length(), (DOMDocumentType) curr); @@ -578,8 +567,8 @@ else if((curr.isClosed())) { } case DTDEndTag: { - if ((curr.isDTDElementDecl() || curr.isDTDAttListDecl() || curr.isDTDEntityDecl() || curr.isDTDNotationDecl()) && curr.parent != null) { - if(curr.isDTDNotationDecl() && curr.parent.isDoctype() == false) { + if ((curr.isDTDElementDecl() || curr.isDTDAttListDecl() || curr.isDTDEntityDecl() || curr.isDTDNotationDecl()) ) { + while(curr.parent != null && !curr.parent.isDoctype()) { curr = curr.parent; } curr.end = scanner.getTokenEnd(); @@ -590,7 +579,7 @@ else if((curr.isClosed())) { } case DTDEndDoctypeTag: { - ((DOMDocumentType) curr).setEnd(scanner.getTokenEnd()); + ((DOMDocumentType) curr).end = scanner.getTokenEnd(); curr.closed = true; curr = curr.parent; break; @@ -598,8 +587,7 @@ else if((curr.isClosed())) { case DTDUnrecognizedParameters: { DTDDeclNode node = (DTDDeclNode) curr; - node.unrecognizedStart = scanner.getTokenOffset(); - node.unrecognizedEnd = scanner.getTokenEnd(); + node.setUnrecognized(scanner.getTokenOffset(), ((XMLScanner)scanner).getLastNonWhitespaceOffset()); break; } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDAttlistDecl.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDAttlistDecl.java index 519b80fb6b..fa75a2300e 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDAttlistDecl.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDAttlistDecl.java @@ -34,20 +34,16 @@ public class DTDAttlistDecl extends DTDDeclNode { * > */ - Integer elementNameStart, elementNameEnd; - Integer attributeNameStart, attributeNameEnd; - Integer attributeTypeStart, attributeTypeEnd; - Integer attributeValueStart, attributeValueEnd; + public DTDDeclParameter elementName; + public DTDDeclParameter attributeName; + public DTDDeclParameter attributeType; + public DTDDeclParameter attributeValue; - String elementName; - String attributeName; - String attributeType; - String attributeValue; - - ArrayList internalChildren; + ArrayList internalChildren; //Holds all additional internal attlist declaractions public DTDAttlistDecl(int start, int end, DOMDocumentType parentDocumentType) { super(start, end, parentDocumentType); + setDeclType(start + 2, start + 9); } public DOMDocumentType getParentDocumentType() { @@ -65,8 +61,11 @@ public String getNodeName() { * @return the element name */ public String getElementName() { - elementName = getValueFromOffsets(parentDocumentType, elementName, elementNameStart, elementNameEnd); - return elementName; + return elementName != null ? elementName.getParameter() : null; + } + + public void setElementName(int start, int end) { + elementName = addNewParameter(start, end); } /** @@ -75,18 +74,27 @@ public String getElementName() { * @return the attribute name */ public String getAttributeName() { - attributeName = getValueFromOffsets(parentDocumentType, attributeName, attributeNameStart, attributeNameEnd); - return attributeName; + return attributeName != null ? attributeName.getParameter() : null; + } + + public void setAttributeName(int start, int end) { + attributeName = addNewParameter(start, end); } public String getAttributeType() { - attributeType = getValueFromOffsets(parentDocumentType, attributeType, attributeTypeStart, attributeTypeEnd); - return attributeType; + return attributeType != null ? attributeType.getParameter() : null; + } + + public void setAttributeType(int start, int end) { + attributeType = addNewParameter(start, end); } public String getAttributeValue() { - attributeValue = getValueFromOffsets(parentDocumentType, attributeValue, attributeValueStart, attributeValueEnd); - return attributeValue; + return attributeValue != null ? attributeValue.getParameter() : null; + } + + public void setAttributeValue(int start, int end) { + attributeValue = addNewParameter(start, end); } @Override diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDDeclNode.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDDeclNode.java index 12c3103baf..5e9803663e 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDDeclNode.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDDeclNode.java @@ -12,6 +12,9 @@ package org.eclipse.lsp4xml.dom; +import java.util.ArrayList; + + /** * DTDNode */ @@ -25,14 +28,23 @@ public class DTDDeclNode extends DOMNode{ */ protected final DOMDocumentType parentDocumentType; + protected final DOMDocument parentDocument; - Integer unrecognizedStart, unrecognizedEnd; + public DTDDeclParameter unrecognized; // holds all content after parsing goes wrong in a DTD declaration (ENTITY, ATTLIST, ...). + public DTDDeclParameter declType; // represents the actual name of the decl eg: ENTITY, ATTLIST, ... - String unrecognized; // holds all content after parsing goes wrong in a DTD declaration (ENTITY, ATTLIST, ELEMENT). + ArrayList parameters; public DTDDeclNode(int start, int end, DOMDocumentType parentDocumentType) { super(start, end, parentDocumentType != null ? parentDocumentType.getOwnerDocument() : null); this.parentDocumentType = parentDocumentType; + this.parentDocument = null; + } + + public DTDDeclNode(int start, int end, DOMDocument parentDocumentType) { + super(start, end, parentDocumentType != null ? parentDocumentType : null); + this.parentDocument = parentDocumentType; + this.parentDocumentType = null; } @Override @@ -46,8 +58,11 @@ public short getNodeType() { } public String getUnrecognized() { - unrecognized = getValueFromOffsets(parentDocumentType, unrecognized, unrecognizedStart, unrecognizedEnd); - return unrecognized; + return unrecognized.getParameter(); + } + + public void setUnrecognized(int start, int end) { + unrecognized = addNewParameter(start, end); } public static String getValueFromOffsets(DOMDocumentType document, String value, Integer start, Integer end) { @@ -55,7 +70,42 @@ public static String getValueFromOffsets(DOMDocumentType document, String value, return document.getSubstring(start, end); } return value; + } + + public DTDDeclParameter addNewParameter(int start, int end) { + if(parameters == null) { + parameters = new ArrayList(); + } + DTDDeclParameter parameter = + new DTDDeclParameter(parentDocumentType == null ? parentDocument.getDoctype() : parentDocumentType, start, end); + parameters.add(parameter); + this.end = end; // updates end position of the node. + return parameter; } - + public void updateLastParameterEnd(int end) { + if(parameters != null && parameters.size() > 0) { + DTDDeclParameter last = parameters.get(parameters.size() - 1); + last.end = end; + this.end = end; + } + } + + public ArrayList getParameters() { + if(parameters == null) { + parameters = new ArrayList(); + } + return parameters; + } + + public void setDeclType(int start, int end) { + declType = new DTDDeclParameter(parentDocumentType, start, end); + } + + public String getDeclType() { + if(declType != null) { + return declType.getParameter(); + } + return null; + } } \ No newline at end of file diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDDeclParameter.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDDeclParameter.java new file mode 100644 index 0000000000..e36a77a66a --- /dev/null +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDDeclParameter.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2018 Red Hat Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Red Hat Inc. - initial API and implementation + * + *******************************************************************************/ + +package org.eclipse.lsp4xml.dom; + +/** + * DTDDeclParameter + */ +public class DTDDeclParameter { + + String parameter; + + int start, end; + + DOMDocumentType parentDoctype; + + public DTDDeclParameter(DOMDocumentType doctype, int start, int end) { + this.parentDoctype = doctype; + this.start = start; + this.end = end; + } + + public int getStart() { + return start; + } + + public int getEnd() { + return end; + } + + public String getParameter() { + if (parameter == null) { + parameter = parentDoctype.getSubstring(start, end); + } + return parameter; + } + + /** + * Will get the parameter with the first and last character removed + * + * Can be used to remove the quotations from a URL value... + */ + public String getParameterWithoutFirstAndLastChar() { + if (parameter == null) { + parameter = parentDoctype.getSubstring(start + 1, end - 1); + } + return parameter; + } + + + @Override + public boolean equals(Object obj) { + if(!(obj instanceof DTDDeclParameter)) { + return false; + } + DTDDeclParameter temp = (DTDDeclParameter) obj; + return start == temp.start && end == temp.end; + } + + + +} \ No newline at end of file diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDElementDecl.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDElementDecl.java index 7d9673288b..50abc4a439 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDElementDecl.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDElementDecl.java @@ -27,17 +27,14 @@ public class DTDElementDecl extends DTDDeclNode { */ - Integer nameStart, nameEnd; // - Integer categoryStart, categoryEnd; // - Integer contentStart,contentEnd; // - - String name; - String category; - String content; + public DTDDeclParameter name; + public DTDDeclParameter category; + public DTDDeclParameter content; public DTDElementDecl(int start, int end, DOMDocumentType parentDocumentType) { super(start, end, parentDocumentType); + setDeclType(start + 2, start + 9); } public DOMDocumentType getParentDocumentType() { @@ -50,18 +47,27 @@ public String getNodeName() { } public String getName() { - name = getValueFromOffsets(parentDocumentType, name, nameStart, nameEnd); - return name; + return name != null ? name.getParameter() : null; + } + + public void setName(int start, int end) { + name = addNewParameter(start, end); } public String getCategory() { - category = getValueFromOffsets(parentDocumentType, category, categoryStart, categoryEnd); - return category; + return category != null ? category.getParameter() : null; + } + + public void setCategory(int start, int end) { + category = addNewParameter(start, end); } public String getContent() { - content = getValueFromOffsets(parentDocumentType, content, contentStart, contentEnd); - return content; + return content != null ? content.getParameter() : null; + } + + public void setContent(int start, int end) { + content = addNewParameter(start, end); } @Override @@ -78,4 +84,5 @@ public int getEndElementTag() { return getStart() + " */ - - String name; - String value; - String kind; - String publicId; - String systemId; - - Integer percentStart, percentEnd; - Integer nameStart, nameEnd; - Integer valueStart, valueEnd; - Integer kindStart, kindEnd; - Integer publicIdStart, publicIdEnd; - Integer systemIdStart, systemIdEnd; + DTDDeclParameter percent; + DTDDeclParameter name; + DTDDeclParameter value; + DTDDeclParameter kind; + DTDDeclParameter publicId; + DTDDeclParameter systemId; public DTDEntityDecl(int start, int end, DOMDocumentType parentDocumentType) { super(start, end, parentDocumentType); + setDeclType(start + 2, start + 8); } public String getPercent() { - if(percentStart != null && percentEnd != null) { - return "%"; - } - return null; + return percent != null ? percent.getParameter() : null; + } + + public void setPercent(int start, int end) { + percent = addNewParameter(start, end); } /* @@ -79,18 +74,27 @@ public String getPercent() { */ @Override public String getNodeName() { - name = getValueFromOffsets(parentDocumentType, name, nameStart, nameEnd); - return name; + return name != null ? name.getParameter() : null; + } + + public void setNodeName(int start, int end) { + name = addNewParameter(start, end); } public String getValue() { - value = getValueFromOffsets(parentDocumentType, value, valueStart, valueEnd); - return value; + return value != null ? value.getParameter() : null; + } + + public void setValue(int start, int end) { + value = addNewParameter(start, end); } public String getKind() { - kind = getValueFromOffsets(parentDocumentType, kind, kindStart, kindEnd); - return kind; + return kind != null ? kind.getParameter() : null; + } + + public void setKind(int start, int end) { + kind = addNewParameter(start, end); } @Override @@ -125,8 +129,11 @@ public String getNotationName() { */ @Override public String getPublicId() { - publicId = getValueFromOffsets(parentDocumentType, publicId, publicIdStart, publicIdEnd); - return publicId; + return publicId != null ? publicId.getParameter() : null; + } + + public void setPublicId(int start, int end) { + publicId = addNewParameter(start, end); } /* @@ -136,8 +143,11 @@ public String getPublicId() { */ @Override public String getSystemId() { - systemId = getValueFromOffsets(parentDocumentType, systemId, systemIdStart, systemIdEnd); - return systemId; + return systemId != null ? systemId.getParameter() : null; + } + + public void setSystemId(int start, int end) { + systemId = addNewParameter(start, end); } /* @@ -159,5 +169,4 @@ public String getXmlEncoding() { public String getXmlVersion() { throw new UnsupportedOperationException(); } - } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDNotationDecl.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDNotationDecl.java index f8b1aaa041..44ecc29c66 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDNotationDecl.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDNotationDecl.java @@ -33,58 +33,46 @@ public class DTDNotationDecl extends DTDDeclNode { * */ - Integer nameStart, nameEnd; - Integer kindStart, kindEnd; - Integer publicIdStart, publicIdEnd; - Integer systemIdStart, systemIdEnd; - - String name; - String kind; - String publicId; - String systemId; + DTDDeclParameter name; + DTDDeclParameter kind; + DTDDeclParameter publicId; + DTDDeclParameter systemId; public DTDNotationDecl(int start, int end, DOMDocumentType parentDocumentType) { super(start, end, parentDocumentType); + setDeclType(start + 2, start + 10); } void setName(int start, int end) { - nameStart = start; - nameEnd = end; + name = addNewParameter(start, end); } public String getName() { - name = getValueFromOffsets(parentDocumentType, name, nameStart, nameEnd); - return name; + return name != null ? name.getParameter() : null; } void setKind(int start, int end) { - kindStart = start; - kindEnd = end; + kind = addNewParameter(start, end); } public String getKind() { - kind = getValueFromOffsets(parentDocumentType, kind, kindStart, kindEnd); - return kind; + return kind != null ? kind.getParameter() : null; } void setPublicId(int start, int end) { - publicIdStart = start; - publicIdEnd = end; + publicId = addNewParameter(start, end); } public String getPublicId() { - publicId = getValueFromOffsets(parentDocumentType, publicId, publicIdStart, publicIdEnd); - return publicId; + return publicId != null ? publicId.getParameter() : null; } void setSystemId(int start, int end) { - systemIdStart = start; - systemIdEnd = end; + systemId = addNewParameter(start, end); } public String getSystemId() { - systemId = getValueFromOffsets(parentDocumentType, systemId, systemIdStart, systemIdEnd); - return systemId; + return systemId != null ? systemId.getParameter() : null; } @Override diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDUnrecognizedDeclParameter.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDUnrecognizedDeclParameter.java new file mode 100644 index 0000000000..aaaf434a03 --- /dev/null +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/DTDUnrecognizedDeclParameter.java @@ -0,0 +1,15 @@ +package org.eclipse.lsp4xml.dom; + +/** + DTDUnrecognizedDeclParamater + */ +public class DTDUnrecognizedDeclParameter extends DTDDeclParameter { + public DTDUnrecognizedDeclParameter(DOMDocumentType doctype, int start, int end) { + super(doctype, start, end); + } + + @Override + public String getParameter() { + return super.getParameter().trim(); + } +} \ No newline at end of file diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/LineIndentInfo.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/LineIndentInfo.java index 437dd4d29a..2089faebc0 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/LineIndentInfo.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/LineIndentInfo.java @@ -1,3 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2018 Red Hat Inc. and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Angelo Zerr. - initial API and implementation + * + *******************************************************************************/ + package org.eclipse.lsp4xml.dom; public class LineIndentInfo { diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/Constants.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/Constants.java index a223578343..319825447b 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/Constants.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/Constants.java @@ -51,6 +51,8 @@ public class Constants { public final static int _mVL = "m".codePointAt(0); public final static int _lVL = "l".codePointAt(0); public final static int _PCT = "%".codePointAt(0); + public final static int _AST = "*".codePointAt(0); + public final static int _PLS = "+".codePointAt(0); public static final Pattern ENTITY_NAME_REGEX = Pattern.compile(""); @@ -70,7 +72,7 @@ public class Constants { public static final Pattern DTD_ELEMENT_CATEGORY = Pattern.compile("^(EMPTY|ANY)([\\s<>\"'])"); - public static final Pattern DTD_ELEMENT_CONTENT = Pattern.compile("^(\\(((\\S,)*(\\S))\\)|\\(\\))"); + public static final Pattern DTD_ELEMENT_CONTENT = Pattern.compile("^(\\((([^\\s,]+,)*[^\\s,]+)\\))|\\(\\)"); public static final Pattern DTD_PCDATA = Pattern.compile("^#PCDATA"); diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/MultiLineStream.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/MultiLineStream.java index 7f5d13629e..56ecf331cf 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/MultiLineStream.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/MultiLineStream.java @@ -16,6 +16,11 @@ import static org.eclipse.lsp4xml.dom.parser.Constants._NWL; import static org.eclipse.lsp4xml.dom.parser.Constants._TAB; import static org.eclipse.lsp4xml.dom.parser.Constants._WSP; +import static org.eclipse.lsp4xml.dom.parser.Constants._LAN; +import static org.eclipse.lsp4xml.dom.parser.Constants._RAN; +import static org.eclipse.lsp4xml.dom.parser.Constants._OSB; +import static org.eclipse.lsp4xml.dom.parser.Constants._CSB; + import java.util.HashMap; import java.util.Map; @@ -100,6 +105,18 @@ public int peekChar(int n) { return this.source.codePointAt(pos); } + /** + * Peeks at the char at position 'offset' of the whole document + * @param offset + * @return + */ + public int peekCharAtOffset(int offset) { + if (offset >= len || offset < 0) { + return -1; + } + return this.source.codePointAt(offset); + } + public boolean advanceIfChar(int ch) { if (ch == peekChar()) { this.position++; @@ -122,6 +139,19 @@ public boolean advanceIfChars(int... ch) { return true; } + public int advanceIfAnyOfChars(int... ch) { + int i; + if (this.position + 1 > this.len) { + return -1; + } + for (i = 0; i < ch.length; i++) { + if (advanceIfChar(ch[i])) { + return ch[i]; + } + } + return -1; + } + public String advanceIfRegExp(Pattern regex) { Matcher match = getCachedMatcher(regex); // Initialize start region where search must be started. @@ -202,6 +232,40 @@ public boolean advanceUntilCharOrNewTag(int ch) { return false; } + /** + * Will advance the stream position until 'closingBracket' or using a stack + * to consider possible open/closed bracket pairs in between. + * + * 'closingBracket' should be the closing bracket eg: > | ] + */ + public boolean advanceUntilCharUsingStack(int closingBracket) { + + int openingBracket; + if(closingBracket == _RAN) { // > + openingBracket = _LAN;// < + } + else if(closingBracket == _CSB) { // ] + openingBracket = _OSB; // [ + } + else { + return false; // The provided closingBracket is not implemented + } + int stack = 0; + while (this.position < this.len) { + if(peekChar() == openingBracket) { + stack ++; + } + else if(peekChar() == closingBracket) { + if(stack == 0) { + return true; + } + stack--; + } + this.advance(1); + } + return false; + } + public boolean advanceUntilChars(int... ch) { while (this.position + ch.length <= this.len) { int i = 0; @@ -272,4 +336,12 @@ private Matcher getCachedMatcher(Pattern regex) { } return matcher; } + + public int getLastNonWhitespaceOffset() { + int posNow = this.position; + while (posNow > 0 && WHITESPACE_PREDICATE.test(peekCharAtOffset(posNow - 1))) { + posNow--; + } + return posNow; + } } \ No newline at end of file diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/ScannerState.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/ScannerState.java index ef95578b65..624654bd65 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/ScannerState.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/ScannerState.java @@ -26,6 +26,6 @@ public enum ScannerState { DTDElementAfterName, DTDElementWithinContent, DTDAfterAttlistName, DTDAfterAttlistElementName, DTDAfterAttlistAttributeName, DTDAfterAttlistAttributeType, DTDAfterEntityName, DTDUnrecognizedParameters, DTDWithinNotation, DTDAfterNotationName, DTDAfterNotationPUBLIC, DTDAfterNotationSYSTEM, - DTDAfterNotationPublicId, DTDAfterEntityPUBLIC, DTDAfterEntitySYSTEM; + DTDAfterNotationPublicId, DTDAfterEntityPUBLIC, DTDAfterEntitySYSTEM, DoctypeUnrecognizedParameters; } \ No newline at end of file diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/XMLScanner.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/XMLScanner.java index 00d307250b..1b59f1e452 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/XMLScanner.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/dom/parser/XMLScanner.java @@ -34,26 +34,28 @@ public class XMLScanner implements Scanner { String url; boolean isInsideDTDContent = false; // Either internal dtd in xml file OR external dtd in dtd file boolean isDeclCompleted = false; // If any type of DTD declaration was supplied with all the required properties - + TokenType tempToken; + boolean isDTDFile; /** * boolean completedInitialAttDef; * * If the first attribute definition was completed in an ATTLIST declaration * eg: * */ boolean isInitialAttlistDeclCompleted = false; private int nbBraceOpened; - public XMLScanner(String input, int initialOffset, ScannerState initialState) { + public XMLScanner(String input, int initialOffset, ScannerState initialState, boolean isDTDFile) { stream = new MultiLineStream(input, initialOffset); state = initialState; tokenOffset = 0; isInsideDTDContent = ScannerState.DTDWithinContent.equals(initialState); tokenType = TokenType.Unknown; + this.isDTDFile = isDTDFile; } String nextElementName() { @@ -65,7 +67,7 @@ String nextAttributeName() { } String doctypeName() { - return stream.advanceIfRegExp(ATTRIBUTE_NAME_REGEX).toLowerCase(); + return stream.advanceIfRegExp(ELEMENT_NAME_REGEX).toLowerCase(); } /** @@ -394,7 +396,7 @@ TokenType internalScan() { state = ScannerState.DTDAfterDoctypeSYSTEM; return finishToken(offset, TokenType.DTDDocTypeKindSYSTEM); } - state = ScannerState.DTDWithinDoctype; + state = ScannerState.DTDUnrecognizedParameters; return internalScan(); case DTDAfterDoctypePUBLIC: @@ -407,7 +409,7 @@ TokenType internalScan() { return finishToken(offset, TokenType.DTDDoctypePublicId); } - state = ScannerState.DTDWithinDoctype; + state = ScannerState.DTDUnrecognizedParameters; return internalScan(); case DTDAfterDoctypeSYSTEM: @@ -420,6 +422,8 @@ TokenType internalScan() { if (!url.equals("")) { return finishToken(offset, TokenType.DTDDoctypeSystemId); } + + state = ScannerState.DTDUnrecognizedParameters; return internalScan(); case DTDAfterDoctypePublicId: @@ -432,10 +436,12 @@ TokenType internalScan() { if (!url.equals("")) { return finishToken(offset, TokenType.DTDDoctypeSystemId); } + + state = ScannerState.DTDUnrecognizedParameters; return internalScan(); case DTDWithinContent: - if (stream.advanceIfChar(_CSB)) { // ] + if (!isDTDFile && (stream.advanceIfChar(_CSB) || stream.peekChar() == _RAN)) { // ] || > state = ScannerState.DTDWithinDoctype; isInsideDTDContent = false; return finishToken(offset, TokenType.DTDEndInternalSubset); @@ -468,16 +474,14 @@ TokenType internalScan() { return finishToken(offset, TokenType.Content); } } - - if (stream.advanceIfChar(_CSB)) { // ] - state = ScannerState.DTDWithinDoctype; - isInsideDTDContent = false; - return finishToken(offset, TokenType.DTDEndInternalSubset); + if(isDTDFile) { + stream.advanceUntilChar(_LAN); // < + } else { + stream.advanceUntilAnyOfChars(_RAN, _LAN, _CSB); // > || < || ] } - - stream.advanceUntilAnyOfChars(_LAN, _CSB); // < || ] return finishToken(offset, TokenType.Content); + case DTDUnrecognizedParameters: @@ -486,12 +490,13 @@ TokenType internalScan() { } if(stream.advanceIfChar(_RAN)) { // > - state = ScannerState.DTDWithinContent; - return finishToken(offset, TokenType.DTDEndTag); + state = isInsideDTDContent ? ScannerState.DTDWithinContent : ScannerState.WithinContent; + tempToken = isInsideDTDContent ? TokenType.DTDEndTag : TokenType.EndTagClose; + return finishToken(offset, tempToken); } if(stream.peekChar() == _LAN) { // < - state = ScannerState.DTDWithinContent; + state = isInsideDTDContent ? ScannerState.DTDWithinContent : ScannerState.WithinContent; return internalScan(); } @@ -500,9 +505,19 @@ TokenType internalScan() { return internalScan(); } + //If in DOCTYPE this will skip over the whole internal subset + if(!isInsideDTDContent) { + stream.advanceUntilAnyOfChars(_OSB, _RAN, _LAN); // [ | < | > + if(stream.peekChar() == _OSB) { + stream.advance(1); + stream.advanceUntilCharUsingStack(_CSB);// ] + + } + } + if(stream.advanceUntilCharOrNewTag(_RAN)) { // > if(stream.peekChar() == _LAN) { // < - state = ScannerState.DTDWithinContent; + state = isInsideDTDContent ? ScannerState.DTDWithinContent : ScannerState.DTDWithinDoctype; } } return finishToken(offset, TokenType.DTDUnrecognizedParameters); @@ -556,6 +571,7 @@ TokenType internalScan() { if(stream.advanceIfChar(_CRB)) { // ) isDeclCompleted = true; state = ScannerState.DTDWithinElement; + stream.advanceIfAnyOfChars(_QMA, _AST, _PLS); // ? | * | + return finishToken(offset, TokenType.DTDEndElementContent); } @@ -852,6 +868,10 @@ private String localize(String string, String string2) { return string; } + public int getLastNonWhitespaceOffset() { + return stream.getLastNonWhitespaceOffset(); + } + @Override public TokenType getTokenType() { return tokenType; @@ -913,13 +933,17 @@ public static Scanner createScanner(String input, int initialOffset) { return createScanner(input, initialOffset, false); } - public static Scanner createScanner(String input, int initialOffset, boolean insideDTD) { + public static Scanner createScanner(String input, int initialOffset, boolean isDTDFile) { return createScanner(input, initialOffset, - insideDTD ? ScannerState.DTDWithinContent : ScannerState.WithinContent); + isDTDFile ? ScannerState.DTDWithinContent : ScannerState.WithinContent, isDTDFile); } public static Scanner createScanner(String input, int initialOffset, ScannerState initialState) { - return new XMLScanner(input, initialOffset, initialState); + return new XMLScanner(input, initialOffset, initialState, false); + } + + public static Scanner createScanner(String input, int initialOffset, ScannerState initialState, boolean isDTDFile) { + return new XMLScanner(input, initialOffset, initialState, isDTDFile); } } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/participants/DTDErrorCode.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/participants/DTDErrorCode.java index 341bd383ae..509a47e756 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/participants/DTDErrorCode.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/contentmodel/participants/DTDErrorCode.java @@ -14,7 +14,9 @@ import java.util.Map; import org.apache.xerces.xni.XMLLocator; +import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4xml.commons.BadLocationException; import org.eclipse.lsp4xml.dom.DOMDocument; import org.eclipse.lsp4xml.dom.DOMElement; import org.eclipse.lsp4xml.extensions.contentmodel.participants.codeactions.ElementDeclUnterminatedCodeAction; @@ -30,12 +32,40 @@ */ public enum DTDErrorCode implements IXMLErrorCode { - MSG_ELEMENT_NOT_DECLARED, MSG_CONTENT_INCOMPLETE, MSG_CONTENT_INVALID, MSG_REQUIRED_ATTRIBUTE_NOT_SPECIFIED, - MSG_ATTRIBUTE_NOT_DECLARED, MSG_ATTRIBUTE_VALUE_NOT_IN_LIST, MSG_FIXED_ATTVALUE_INVALID, - MSG_ELEMENT_WITH_ID_REQUIRED, IDInvalidWithNamespaces, IDREFInvalidWithNamespaces, IDREFSInvalid, + + + MSG_ELEMENT_TYPE_REQUIRED_IN_ELEMENTDECL , + ElementDeclUnterminated, + EntityDeclUnterminated, + AttlistDeclUnterminated, + NotationDeclUnterminated, + MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN, - MSG_ELEMENT_TYPE_REQUIRED_IN_ELEMENTDECL, MSG_MARKUP_NOT_RECOGNIZED_IN_DTD, ElementDeclUnterminated, - MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN; + MSG_ELEMENT_NOT_DECLARED, + IDREFSInvalid, + MSG_REQUIRED_ATTRIBUTE_NOT_SPECIFIED, + MSG_FIXED_ATTVALUE_INVALID, + IDInvalidWithNamespaces, + MSG_ELEMENT_WITH_ID_REQUIRED, + MSG_CONTENT_INCOMPLETE, + MSG_CONTENT_INVALID, + MSG_MARKUP_NOT_RECOGNIZED_IN_DTD, + IDREFInvalidWithNamespaces, + MSG_ATTRIBUTE_NOT_DECLARED, + MSG_ATTRIBUTE_VALUE_NOT_IN_LIST, + MSG_ENTITY_NAME_REQUIRED_IN_ENTITYDECL, + MSG_ELEMENT_TYPE_REQUIRED_IN_ATTLISTDECL, + MSG_NOTATION_NAME_REQUIRED_IN_NOTATIONDECL, + ExternalIDorPublicIDRequired, + QuoteRequiredInPublicID, + AttNameRequiredInAttDef, + OpenQuoteExpected, + LessthanInAttValue, + AttTypeRequiredInAttDef, + MSG_SPACE_REQUIRED_AFTER_NOTATION_NAME_IN_NOTATIONDECL, + SpaceRequiredAfterSYSTEM, + OpenQuoteMissingInDecl, + QuoteRequiredInSystemID; private final String code; @@ -87,7 +117,7 @@ public static Range toLSPRange(XMLLocator location, DTDErrorCode code, Object[] case MSG_CONTENT_INVALID: return XMLPositionUtility.selectStartTag(offset, document); case MSG_ATTRIBUTE_NOT_DECLARED: - return XMLPositionUtility.selectAttributeNameAt(offset, document); + return XMLPositionUtility.selectAttributeValueAt((String)arguments[1], offset, document); case MSG_FIXED_ATTVALUE_INVALID: { String attrName = (String) arguments[1]; return XMLPositionUtility.selectAttributeValueAt(attrName, offset, document); @@ -96,6 +126,7 @@ public static Range toLSPRange(XMLLocator location, DTDErrorCode code, Object[] String attrName = (String) arguments[0]; return XMLPositionUtility.selectAttributeValueAt(attrName, offset, document); } + case MSG_ELEMENT_WITH_ID_REQUIRED: { DOMElement element = document.getDocumentElement(); if (element != null) { @@ -109,14 +140,52 @@ public static Range toLSPRange(XMLLocator location, DTDErrorCode code, Object[] return XMLPositionUtility.selectAttributeValueByGivenValueAt(attrValue, offset, document); } + case MSG_MARKUP_NOT_RECOGNIZED_IN_DTD: { + return XMLPositionUtility.selectWholeTag(offset + 1, document); + } + // ---------- DTD Doc type - case MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN: + case QuoteRequiredInPublicID: { + return XMLPositionUtility.getLastValidDTDDeclParameterOrUnrecognized(offset, document); + } + + case ExternalIDorPublicIDRequired: { + return XMLPositionUtility.getLastValidDTDDeclParameter(offset, document); + } + + case QuoteRequiredInSystemID: + case OpenQuoteMissingInDecl: + case SpaceRequiredAfterSYSTEM: + case MSG_SPACE_REQUIRED_AFTER_NOTATION_NAME_IN_NOTATIONDECL: + case AttTypeRequiredInAttDef: + case LessthanInAttValue: + case OpenQuoteExpected: + case AttNameRequiredInAttDef: + case EntityDeclUnterminated: + case AttlistDeclUnterminated: + case NotationDeclUnterminated: case ElementDeclUnterminated: { - return XMLPositionUtility.selectDTDElementDeclAt(offset, document); + return XMLPositionUtility.getLastValidDTDDeclParameterOrUnrecognized(offset, document); + //return XMLPositionUtility.selectDTDElementDeclAt(offset, document); + } + + case MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN: { + return XMLPositionUtility.getElementDeclMissingContentOrCategory(offset, document); } + + + case MSG_NOTATION_NAME_REQUIRED_IN_NOTATIONDECL: + case MSG_ENTITY_NAME_REQUIRED_IN_ENTITYDECL: + case MSG_ELEMENT_TYPE_REQUIRED_IN_ATTLISTDECL: case MSG_ELEMENT_TYPE_REQUIRED_IN_ELEMENTDECL: { - return XMLPositionUtility.selectDTDElementDeclTagAt(offset, document); + return XMLPositionUtility.selectDTDDeclTagNameAt(offset, document); } + default: + try { + return new Range(new Position(0, 0), document.positionAt(document.getEnd())); + } catch (BadLocationException e) { + + } } return null; } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/dtd/contentmodel/CMDTDContentModelProvider.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/dtd/contentmodel/CMDTDContentModelProvider.java index 80c3d64ada..ee09136dcd 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/dtd/contentmodel/CMDTDContentModelProvider.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/extensions/dtd/contentmodel/CMDTDContentModelProvider.java @@ -53,7 +53,7 @@ public String getSystemId(DOMDocument xmlDocument, String namespaceURI) { * "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd"> */ DOMDocumentType documentType = xmlDocument.getDoctype(); - return documentType.getSystemId(); + return documentType.getSystemIdWithoutQuotes(); } @Override diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/XMLFormatter.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/XMLFormatter.java index 048c3244ca..032609ab3b 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/XMLFormatter.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/services/XMLFormatter.java @@ -11,6 +11,7 @@ package org.eclipse.lsp4xml.services; import java.util.ArrayList; +import java.util.Iterator; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -30,8 +31,12 @@ import org.eclipse.lsp4xml.dom.DOMParser; import org.eclipse.lsp4xml.dom.DOMProcessingInstruction; import org.eclipse.lsp4xml.dom.DOMText; +import org.eclipse.lsp4xml.dom.DTDAttlistDecl; +import org.eclipse.lsp4xml.dom.DTDDeclNode; +import org.eclipse.lsp4xml.dom.DTDDeclParameter; import org.eclipse.lsp4xml.services.extensions.XMLExtensionsRegistry; import org.eclipse.lsp4xml.settings.XMLFormattingOptions; +import org.eclipse.lsp4xml.utils.StringUtils; import org.eclipse.lsp4xml.utils.XMLBuilder; /** @@ -66,7 +71,7 @@ public List format(TextDocument document, Range range, XMLFo // Parse the content to format to create an XML document with full data (CData, // comments, etc) String text = document.getText().substring(start, end); - DOMDocument doc = DOMParser.getInstance().parse(text, null, null); + DOMDocument doc = DOMParser.getInstance().parse(text, document.getUri(), null); // Format the content XMLBuilder xml = new XMLBuilder(formattingOptions, "", document.lineDelimiter(startPosition.getLine())); @@ -86,9 +91,14 @@ public List format(TextDocument document, Range range, XMLFo private void format(DOMNode node, int level, int end, XMLBuilder xml) { if (node.getNodeType() != DOMNode.DOCUMENT_NODE) { - boolean doLineFeed = !(node.isComment() && ((DOMComment) node).isCommentSameLineEndTag()) + boolean doLineFeed; + if(node.getOwnerDocument().isDTD()) { + doLineFeed = false; + } else { + doLineFeed = !(node.isComment() && ((DOMComment) node).isCommentSameLineEndTag()) && (!isPreviousNodeType(node, DOMNode.TEXT_NODE) || xml.isJoinContentLines()) && (!node.isText() || ((xml.isJoinContentLines() && !isFirstChildNode(node)))); + } if (level > 0 && doLineFeed) { // add new line + indent @@ -96,66 +106,7 @@ private void format(DOMNode node, int level, int end, XMLBuilder xml) { xml.indent(level); } // generate start element - if (node.isCDATA()) { - DOMCDATASection cdata = (DOMCDATASection) node; - xml.startCDATA(); - xml.addContentCDATA(cdata.getData()); - xml.endCDATA(); - } else if (node.isComment()) { - DOMComment comment = (DOMComment) node; - xml.startComment(comment); - xml.addContentComment(comment.getData()); - xml.endComment(); - if (level == 0) { - xml.linefeed(); - } - } else if (node.isProcessingInstruction()) { - DOMProcessingInstruction processingInstruction = (DOMProcessingInstruction) node; - xml.startPrologOrPI(processingInstruction.getTarget()); - xml.addContentPI(processingInstruction.getData()); - xml.endPrologOrPI(); - if (level == 0) { - xml.linefeed(); - } - } else if (node.isProlog()) { - DOMProcessingInstruction processingInstruction = (DOMProcessingInstruction) node; - xml.startPrologOrPI(processingInstruction.getTarget()); - if (node.hasAttributes()) { - // generate attributes - String[] attributes = new String[3]; - attributes[0] = "version"; - attributes[1] = "encoding"; - attributes[2] = "standalone"; - - for (int i = 0; i < attributes.length; i++) { - String name = attributes[i]; - String value = node.getAttribute(attributes[i]); - if (value == null) { - continue; - } - xml.addSingleAttribute(name, value); - } - } - xml.endPrologOrPI(); - xml.linefeed(); - } else if (node.isDoctype()) { - DOMDocumentType documentType = (DOMDocumentType) node; - xml.startDoctype(documentType.getName()); - xml.setDoctypeInternalSubset(documentType.getInternalSubset()); - xml.endDoctype(); - xml.linefeed(); - } else if (node.isText()) { - DOMText text = (DOMText) node; - if (text.hasData()) { - // Generate content - String content = text.getData(); - if (!content.isEmpty()) { - xml.addContent(content); - } - - } - return; - } else if (node.isElement()) { + if (node.isElement()) { DOMElement element = (DOMElement) node; String tag = element.getTagName(); if (element.hasEndTag() && !element.hasStartTag()) { @@ -217,6 +168,85 @@ private void format(DOMNode node, int level, int end, XMLBuilder xml) { } } return; + + } else if (node.isCDATA()) { + DOMCDATASection cdata = (DOMCDATASection) node; + xml.startCDATA(); + xml.addContentCDATA(cdata.getData()); + xml.endCDATA(); + } else if (node.isComment()) { + DOMComment comment = (DOMComment) node; + xml.startComment(comment); + xml.addContentComment(comment.getData()); + xml.endComment(); + if (level == 0) { + xml.linefeed(); + } + } else if (node.isProcessingInstruction()) { + DOMProcessingInstruction processingInstruction = (DOMProcessingInstruction) node; + xml.startPrologOrPI(processingInstruction.getTarget()); + xml.addContentPI(processingInstruction.getData()); + xml.endPrologOrPI(); + if (level == 0) { + xml.linefeed(); + } + } else if (node.isProlog()) { + DOMProcessingInstruction processingInstruction = (DOMProcessingInstruction) node; + xml.startPrologOrPI(processingInstruction.getTarget()); + if (node.hasAttributes()) { + // generate attributes + String[] attributes = new String[3]; + attributes[0] = "version"; + attributes[1] = "encoding"; + attributes[2] = "standalone"; + + for (String name : attributes) { + String value = node.getAttribute(name); + if (value == null) { + continue; + } + xml.addSingleAttribute(name, value); + } + } + xml.endPrologOrPI(); + xml.linefeed(); + } else if (node.isText()) { + DOMText text = (DOMText) node; + if (text.hasData()) { + // Generate content + String content = text.getData(); + if (!content.isEmpty()) { + xml.addContent(content); + } + + } + return; + } else if (node.isDoctype()) { + boolean isDTD = node.getOwnerDocument().isDTD(); + DOMDocumentType documentType = (DOMDocumentType) node; + if(!isDTD) { + xml.startDoctype(); + ArrayList params = documentType.getParameters(); + for (DTDDeclParameter param : params) { + if(!documentType.isInternalSubset(param)) { + xml.addParameter(param.getParameter()); + } else { + xml.startDoctypeInternalSubset(); + xml.linefeed(); + // level + 1 since the 'level' value is the doctype tag's level + formatDTD(documentType, level + 1, end, xml); + xml.linefeed(); + xml.endDoctypeInternalSubset(); + } + } + if(documentType.isClosed()) { + xml.endDoctype(); + } + xml.linefeed(); + } else { + formatDTD(documentType, 0, end, xml); + } + return; } } else if (node.hasChildNodes()) { // Other nodes kind like root @@ -226,6 +256,97 @@ private void format(DOMNode node, int level, int end, XMLBuilder xml) { } } + private static boolean formatDTD(DOMDocumentType doctype, int level, int end, XMLBuilder xml) { + DOMNode previous = null; + for (DOMNode node : doctype.getChildren()) { + if(previous != null) { + xml.linefeed(); + } + + xml.indent(level); + + if(node.isText()) { + xml.addContent(((DOMText)node).getData().trim()); + } + else { + if(node.isComment()) { + DOMComment comment = (DOMComment) node; + xml.startComment(comment); + xml.addContentComment(comment.getData()); + xml.endComment(); + } + else { + boolean setEndBracketOnNewLine = false; + DTDDeclNode decl = (DTDDeclNode) node; + xml.addDeclTagStart(decl); + + if(decl.isDTDAttListDecl()) { + DTDAttlistDecl attlist = (DTDAttlistDecl) decl; + ArrayList internalDecls = attlist.getInternalChildren(); + + if(internalDecls == null) { + for (DTDDeclParameter param : decl.getParameters()) { + xml.addParameter(param.getParameter()); + } + } + else { + boolean multipleInternalAttlistDecls = false; + + ArrayList params = attlist.getParameters(); + DTDDeclParameter param; + for(int i = 0; i < params.size(); i++) { + param = params.get(i); + if(attlist.elementName.equals(param)) { + xml.addParameter(param.getParameter()); + if(attlist.getParameters().size() > 1) { //has parameters after elementName + xml.linefeed(); + xml.indent(level + 1); + setEndBracketOnNewLine = true; + multipleInternalAttlistDecls = true; + } + } else { + if(multipleInternalAttlistDecls && i == 1) { + xml.addUnindentedParameter(param.getParameter()); + } else { + xml.addParameter(param.getParameter()); + } + + } + } + + for (DTDAttlistDecl attlistDecl : internalDecls) { + xml.linefeed(); + xml.indent(level + 1); + params = attlistDecl.getParameters(); + for(int i = 0; i < params.size(); i++) { + param = params.get(i); + if(i == 0) { + xml.addUnindentedParameter(param.getParameter()); + } else { + xml.addParameter(param.getParameter()); + } + } + } + } + } else { + for (DTDDeclParameter param : decl.getParameters()) { + xml.addParameter(param.getParameter()); + } + } + if(setEndBracketOnNewLine) { + xml.linefeed(); + xml.indent(level); + } + if(decl.isClosed()) { + xml.closeStartElement(); + } + } + } + previous = node; + } + return true; + } + private static boolean isFirstChildNode(DOMNode node) { return node.equals(node.getParentNode().getFirstChild()); } diff --git a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/utils/XMLBuilder.java b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/utils/XMLBuilder.java index b1381c93b5..1079af1df1 100644 --- a/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/utils/XMLBuilder.java +++ b/org.eclipse.lsp4xml/src/main/java/org/eclipse/lsp4xml/utils/XMLBuilder.java @@ -13,6 +13,9 @@ import static org.eclipse.lsp4xml.utils.StringUtils.normalizeSpace; import org.eclipse.lsp4xml.dom.DOMComment; +import org.eclipse.lsp4xml.dom.DOMDocumentType; +import org.eclipse.lsp4xml.dom.DOMNode; +import org.eclipse.lsp4xml.dom.DTDDeclNode; import org.eclipse.lsp4xml.settings.XMLFormattingOptions; /** @@ -206,21 +209,34 @@ public XMLBuilder addContentComment(String content) { return this; } - public XMLBuilder startDoctype(String name) { + public XMLBuilder addDeclTagStart(DTDDeclNode tag) { + + xml.append(" params = decl.getParameters(); + DTDDeclParameter finalParam; + if(params != null && params.size() == 0) { + return createRange(decl.declType.getStart(), decl.declType.getEnd(), document); + } + else if(params.get(params.size() - 1).equals(decl.unrecognized)) { + finalParam = params.get(params.size() - 2); + } + else { + finalParam = params.get(params.size() - 1); + } + return createRange(finalParam.getEnd(), finalParam.getEnd() + 1, document); + } + return null; + } + + /** + * Will give the range for the last VALID DTD Decl parameter at 'offset'. + * An unrecognized Parameter is not considered VALID, + * + * eg: internal = attlist.getInternalChildren(); + if(internal != null && internal.size() > 0) { + decl = internal.get(internal.size() - 1); //get last internal decl + } + } + ArrayList params = decl.getParameters(); + if(params == null || params.size() == 0) { + return createRange(decl.declType.getStart(), decl.declType.getEnd(), document); + } + DTDDeclParameter finalParam = params.get(params.size() - 1); + if(params.get(params.size() - 1).equals(decl.unrecognized)) { + return createRange(finalParam.getStart(), finalParam.getEnd(), document); + } + return createRange(finalParam.getEnd(), finalParam.getEnd() + 1, document); + } + return null; + } + + /** + * Will give the range for the last VALID DTD Decl parameter at 'offset'. + * An unrecognized Parameter is not considered VALID, + * + * eg: params = decl.getParameters(); + DTDDeclParameter lastParam; + if(params != null && params.size() > 0) { + lastParam = params.get(params.size() - 1); + return createRange(lastParam.getStart(), lastParam.getEnd(), document); + } + } + return null; + } + + public static Range selectDTDDeclTagNameAt(int offset, DOMDocument document) { + DOMNode node = document.findNodeAt(offset); + if (node != null && node instanceof DTDDeclNode) { + DTDDeclNode declNode = (DTDDeclNode) node; + return createRange(declNode.declType.getStart(), declNode.declType.getEnd(), document); } return null; } + public static Range selectWholeTag(int offset, DOMDocument document) { + DOMNode node = document.findNodeAt(offset); + if(node != null) { + return createRange(node.getStart(), node.getEnd(), document); + } + return null; + } + + public static Range getElementDeclMissingContentOrCategory(int offset, DOMDocument document) { + DOMNode node = document.findNodeAt(offset); + if (node != null && node instanceof DTDElementDecl) { + DTDElementDecl declNode = (DTDElementDecl) node; + ArrayList params = declNode.getParameters(); + if(params.size() == 0) { + return null; + } + if(params.size() == 1) { + DTDDeclParameter param = params.get(0); + return createRange(param.getEnd(), param.getEnd() + 1, document); + } + else { + return createRange(params.get(1).getStart(), params.get(1).getEnd(), document); + } + } + return null; + } } diff --git a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/DOMParserForInternalDTDTest.java b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/DOMParserForInternalDTDTest.java index 3bcdbbdf4d..07fc39592b 100644 --- a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/DOMParserForInternalDTDTest.java +++ b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/DOMParserForInternalDTDTest.java @@ -644,8 +644,8 @@ public void attlistWithMultipleInternalDeclarationsMissingInformation() { Assert.assertEquals("CDATA", attlistDecl.getAttributeType()); Assert.assertEquals(null, attlistDecl.getAttributeValue()); - Assert.assertEquals(55, attlistDecl.unrecognizedStart.intValue()); - Assert.assertEquals(75, attlistDecl.unrecognizedEnd.intValue()); + Assert.assertEquals(55, attlistDecl.unrecognized.start); + Assert.assertEquals(75, attlistDecl.unrecognized.end); } @@ -705,7 +705,7 @@ public void allDeclsUnclosed() { DTDElementDecl elementDecl = (DTDElementDecl) documentType.getChild(0); Assert.assertEquals(16, elementDecl.getStart()); - Assert.assertEquals(27, elementDecl.getEnd()); + Assert.assertEquals(28, elementDecl.getEnd()); Assert.assertEquals(null, elementDecl.getName()); Assert.assertEquals(null, elementDecl.getContent()); Assert.assertEquals(null, elementDecl.getCategory()); @@ -714,14 +714,14 @@ public void allDeclsUnclosed() { DTDAttlistDecl attlistDecl = (DTDAttlistDecl) documentType.getChild(1); Assert.assertEquals(28, attlistDecl.getStart()); - Assert.assertEquals(44, attlistDecl.getEnd()); + Assert.assertEquals(45, attlistDecl.getEnd()); Assert.assertEquals("elName", attlistDecl.getElementName()); Assert.assertFalse(attlistDecl.isClosed()); DTDEntityDecl entityDecl = (DTDEntityDecl) documentType.getChild(2); Assert.assertEquals(45, entityDecl.getStart()); - Assert.assertEquals(63, entityDecl.getEnd()); + Assert.assertEquals(64, entityDecl.getEnd()); Assert.assertEquals("garbage", entityDecl.getNodeName()); Assert.assertFalse(entityDecl.isClosed()); @@ -761,8 +761,8 @@ public void dtdUnrecognizedContent() { Assert.assertEquals("elName", elementDecl.getName()); Assert.assertEquals("(aa1,bb2,cc3)", elementDecl.getContent()); Assert.assertEquals(null, elementDecl.getCategory()); - Assert.assertEquals(51, elementDecl.unrecognizedStart.intValue()); - Assert.assertEquals(75, elementDecl.unrecognizedEnd.intValue()); + Assert.assertEquals(51, elementDecl.unrecognized.start); + Assert.assertEquals(75, elementDecl.unrecognized.end); Assert.assertTrue(elementDecl.isClosed()); } @@ -799,6 +799,62 @@ public void dtdNotationComplete() { Assert.assertTrue(elementDecl.isClosed()); } + @Test + public void dtdNotationSYSTEMUnrecognizedParameter() { + + String dtd = + " \n" + + " ]\n" + + ">"; + + DOMDocument actual = createDOMDocument(dtd); + Assert.assertEquals(1, actual.getChildren().size()); + Assert.assertTrue(actual.getChild(0).isDoctype()); + DOMDocumentType documentType = (DOMDocumentType) actual.getChild(0); + Assert.assertEquals(0, documentType.getStart()); + Assert.assertEquals(74, documentType.getEnd()); + Assert.assertEquals("foo", documentType.getName()); + Assert.assertTrue(documentType.isClosed()); + + // \n" + + " ]\n" + + ">"; + + DOMDocument actual = createDOMDocument(dtd); + Assert.assertEquals(1, actual.getChildren().size()); + Assert.assertTrue(actual.getChild(0).isDoctype()); + DOMDocumentType documentType = (DOMDocumentType) actual.getChild(0); + Assert.assertEquals(0, documentType.getStart()); + Assert.assertEquals(84, documentType.getEnd()); + Assert.assertEquals("foo", documentType.getName()); + Assert.assertEquals(14, documentType.unrecognized.start); + Assert.assertEquals(82, documentType.unrecognized.end); + Assert.assertTrue(documentType.isClosed()); + + + } + private static DOMDocument createDOMDocument(String xml) { return DOMParser.getInstance().parse(xml, "uri", null); diff --git a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/DOMParserTest.java b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/DOMParserTest.java index 3504d0ec8d..006aae656c 100644 --- a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/DOMParserTest.java +++ b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/DOMParserTest.java @@ -441,7 +441,7 @@ public void testDoctype2() { " \n" + " \n "; DOMDocument document = DOMParser.getInstance().parse(xml, null, null); - assertDoctype((DOMDocumentType)(document.getChild(0)), 0, 212, "html", DocumentTypeKind.SYSTEM.name(), null, "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd", internal); + assertDoctype((DOMDocumentType)(document.getChild(0)), 0, 212, "html", DocumentTypeKind.SYSTEM.name(), null, "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\"", internal); } @@ -548,7 +548,7 @@ public void testDTDExternalUnrecognizedParameters() { doctype.closed = true; DOMNode entity = createEntityDecl(0, 24, 9, 15, null, null, 16, 22, null, null, null, null, null, null); entity.closed = true; - DOMNode element = createElementDecl(25, 49, 35, 39, null, null, 40, 49, null, null); + DOMNode element = createElementDecl(25, 50, 35, 39, null, null, 40, 49, null, null); element.closed = false; DOMNode attlist = createAttlistDecl(50, 81, 60, 67, 68, 72, null, null, null, null, 73, 80); attlist.closed = true; @@ -571,9 +571,9 @@ public void testDTDExternalUnrecognizedParameters2() { DOMNode doctype = createDoctypeNode(0, 81, null, null, null, null, null, null, null, null, null, null); doctype.closed = true; - DOMNode entity = createEntityDecl(0, 24, 9, 15, null, null, 16, 22, null, null, null, null, null, null); + DOMNode entity = createEntityDecl(0, 25, 9, 15, null, null, 16, 22, null, null, null, null, null, null); entity.closed = false; - DOMNode element = createElementDecl(25, 49, 35, 39, null, null, 40, 49, null, null); + DOMNode element = createElementDecl(25, 50, 35, 39, null, null, 40, 49, null, null); element.closed = false; DOMNode attlist = createAttlistDecl(50, 81, 60, 67, 68, 72, null, null, null, null, 73, 80); attlist.closed = true; @@ -595,7 +595,7 @@ public void testDTDExternalUnrecognizedParameters3() { DOMNode doctype = createDoctypeNode(0, 32, null, null, null, null, null, null, null, null, null, null); doctype.closed = true; - DOMNode attlist = createAttlistDecl(0, 15, 10, 14, null, null, null, null, null, null, null, null); + DOMNode attlist = createAttlistDecl(0, 16, 10, 14, null, null, null, null, null, null, null, null); attlist.closed = false; DOMNode element = createElementDecl(16, 32, 26, 30, null, null, null, null, null, null); element.closed = true; @@ -680,7 +680,7 @@ public void testNotationMissingEndTag() { DOMNode doctype = createDoctypeNode(0, 77, null, null, null, null, null, null, null, null, null, null); doctype.closed = true; - DTDNotationDecl notation1 = createNotationDecl(0, 32, 11, 14, 15, 21, 22, 32, null, null, null, null); + DTDNotationDecl notation1 = createNotationDecl(0, 33, 11, 14, 15, 21, 22, 32, null, null, null, null); notation1.closed = false; DTDNotationDecl notation2 = createNotationDecl(33, 77, 44, 47, 48, 54, 55, 64, 65, 76, null, null); notation2.closed = true; @@ -700,7 +700,7 @@ public void testNotationMissingEndTagMissingAndExtraValues() { DOMNode doctype = createDoctypeNode(0, 81, null, null, null, null, null, null, null, null, null, null); doctype.closed = true; - DTDNotationDecl notation1 = createNotationDecl(0, 32, 11, 14, 15, 21, 22, 32, null, null, null, null); + DTDNotationDecl notation1 = createNotationDecl(0, 33, 11, 14, 15, 21, 22, 32, null, null, null, null); notation1.closed = false; DTDNotationDecl notation2 = createNotationDecl(33, 81, 44, 47, 48, 54, 55, 64, 65, 76, 77, 80); notation2.closed = true; @@ -786,30 +786,21 @@ private static DTDAttlistDecl createAttlistDecl(int start, int end, Integer elem Integer attributeNameEnd, Integer attributeTypeStart, Integer attributeTypeEnd, Integer attributeValueStart, Integer attributeValueEnd, Integer unrecognizedStart, Integer unrecognizedEnd) { DTDAttlistDecl attlist = new DTDAttlistDecl(start, end, null); - attlist.elementNameStart = elementNameStart; - attlist.elementNameEnd = elementNameEnd; - attlist.attributeNameStart = attributeNameStart; - attlist.attributeNameEnd = attributeNameEnd; - attlist.attributeTypeStart = attributeTypeStart; - attlist.attributeTypeEnd = attributeTypeEnd; - attlist.attributeValueStart = attributeValueStart; - attlist.attributeValueEnd = attributeValueEnd; - attlist.unrecognizedStart = unrecognizedStart; - attlist.unrecognizedEnd = unrecognizedEnd; + attlist.elementName = elementNameStart != null ? new DTDDeclParameter(null, elementNameStart, elementNameEnd) : null; + attlist.attributeName = attributeNameStart != null ? new DTDDeclParameter(null, attributeNameStart, attributeNameEnd) : null; + attlist.attributeType = attributeTypeStart != null ? new DTDDeclParameter(null, attributeTypeStart, attributeTypeEnd) : null; + attlist.attributeValue = attributeValueStart != null ? new DTDDeclParameter(null, attributeValueStart, attributeValueEnd) : null; + attlist.unrecognized = unrecognizedStart != null ? new DTDDeclParameter(null, unrecognizedStart, unrecognizedEnd) : null; return attlist; } private static DTDElementDecl createElementDecl(int start, int end, Integer nameStart, Integer nameEnd, Integer categoryStart, Integer categoryEnd, Integer contentStart, Integer contentEnd, Integer unrecognizedStart, Integer unrecognizedEnd) { DTDElementDecl element = new DTDElementDecl(start, end, null); - element.nameStart = nameStart; - element.nameEnd = nameEnd; - element.categoryStart = categoryStart; - element.categoryEnd = categoryEnd; - element.contentStart = contentStart; - element.contentEnd = contentEnd; - element.unrecognizedStart = unrecognizedStart; - element.unrecognizedEnd = unrecognizedEnd; + element.name = nameStart != null ? new DTDDeclParameter(null, nameStart, nameEnd) : null; + element.category = categoryStart != null ? new DTDDeclParameter(null, categoryStart, categoryEnd) : null; + element.content = contentStart != null ? new DTDDeclParameter(null, contentStart, contentEnd) : null; + element.unrecognized = unrecognizedStart != null ? new DTDDeclParameter(null, unrecognizedStart, unrecognizedEnd) : null; return element; } @@ -817,34 +808,23 @@ private static DTDEntityDecl createEntityDecl(int start, int end, Integer nameSt Integer valueEnd, Integer kindStart, Integer kindEnd, Integer publicIdStart, Integer publicIdEnd, Integer systemIdStart, Integer systemIdEnd, Integer unrecognizedStart, Integer unrecognizedEnd) { DTDEntityDecl entity = new DTDEntityDecl(start, end, null); - entity.nameStart = nameStart; - entity.nameEnd = nameEnd; - entity.valueStart = valueStart; - entity.valueEnd = valueEnd; - entity.kindStart = kindStart; - entity.kindEnd = kindEnd; - entity.publicIdStart = publicIdStart; - entity.publicIdEnd = publicIdEnd; - entity.systemIdStart = systemIdStart; - entity.systemIdEnd = systemIdEnd; - entity.unrecognizedStart = unrecognizedStart; - entity.unrecognizedEnd = unrecognizedEnd; + entity.name = nameStart != null ? new DTDDeclParameter(null, nameStart, nameEnd) : null; + entity.value = valueStart != null ? new DTDDeclParameter(null, valueStart, valueEnd) : null; + entity.kind = kindStart != null ? new DTDDeclParameter(null, kindStart, kindEnd) : null; + entity.publicId = publicIdStart != null ? new DTDDeclParameter(null, publicIdStart, publicIdEnd) : null; + entity.systemId = systemIdStart != null ? new DTDDeclParameter(null, systemIdStart, systemIdEnd) : null; + entity.unrecognized = unrecognizedStart != null ? new DTDDeclParameter(null, unrecognizedStart, unrecognizedEnd) : null; return entity; } private static DTDNotationDecl createNotationDecl(int start, int end, Integer nameStart, Integer nameEnd, Integer kindStart, Integer kindEnd, Integer publicIdStart, Integer publicIdEnd, Integer systemIdStart, Integer systemIdEnd, Integer unrecognizedStart, Integer unrecognizedEnd) { DTDNotationDecl notation = new DTDNotationDecl(start, end, null); - notation.nameStart = nameStart; - notation.nameEnd = nameEnd; - notation.kindStart = kindStart; - notation.kindEnd = kindEnd; - notation.publicIdStart = publicIdStart; - notation.publicIdEnd = publicIdEnd; - notation.systemIdStart = systemIdStart; - notation.systemIdEnd = systemIdEnd; - notation.unrecognizedStart = unrecognizedStart; - notation.unrecognizedEnd = unrecognizedEnd; + notation.name = nameStart != null ? new DTDDeclParameter(null, nameStart, nameEnd) : null; + notation.kind = kindStart != null ? new DTDDeclParameter(null, kindStart, kindEnd) : null; + notation.publicId = publicIdStart != null ? new DTDDeclParameter(null, publicIdStart, publicIdEnd) : null; + notation.systemId = systemIdStart != null ? new DTDDeclParameter(null, systemIdStart, systemIdEnd) : null; + notation.unrecognized = unrecognizedStart != null ? new DTDDeclParameter(null, unrecognizedStart, unrecognizedEnd) : null; return notation; } @@ -852,16 +832,11 @@ private static DOMDocumentType createDoctypeNode(int start, int end, Integer nam Integer kindEnd, Integer publicIdStart, Integer publicIdEnd, Integer systemIdStart, Integer systemIdEnd, Integer internalSubsetStart, Integer internalSubsetEnd) { DOMDocumentType doctype = new DOMDocumentType(start, end, null); - doctype.nameStart = nameStart; - doctype.nameEnd = nameEnd; - doctype.kindStart = kindStart; - doctype.kindEnd = kindEnd; - doctype.publicIdStart = publicIdStart; - doctype.publicIdEnd = publicIdEnd; - doctype.systemIdStart = systemIdStart; - doctype.systemIdEnd = systemIdEnd; - doctype.internalSubsetStart = internalSubsetStart; - doctype.internalSubsetEnd = internalSubsetEnd; + doctype.name = nameStart != null ? new DTDDeclParameter(null, nameStart, nameEnd) : null;; + doctype.kind = kindStart != null ? new DTDDeclParameter(null, kindStart, kindEnd) : null;; + doctype.publicId = publicIdStart != null ? new DTDDeclParameter(null, publicIdStart, publicIdEnd) : null;; + doctype.systemId = systemIdEnd != null ? new DTDDeclParameter(null, systemIdStart, systemIdEnd) : null;; + doctype.internalSubset = internalSubsetStart != null ? new DTDDeclParameter(null, internalSubsetStart, internalSubsetEnd) : null;; return doctype; } @@ -1011,16 +986,11 @@ private static void compareTrees(DOMNode expectedNode, DOMNode actualNode) { assertEquals(true, actualNode.isDTDAttListDecl()); DTDAttlistDecl expectedTemp = (DTDAttlistDecl) expectedNode; DTDAttlistDecl actualTemp = (DTDAttlistDecl) actualNode; - assertEquals(expectedTemp.elementNameStart, actualTemp.elementNameStart); - assertEquals(expectedTemp.elementNameEnd, actualTemp.elementNameEnd); - assertEquals(expectedTemp.attributeNameStart, actualTemp.attributeNameStart); - assertEquals(expectedTemp.attributeNameEnd, actualTemp.attributeNameEnd); - assertEquals(expectedTemp.attributeTypeStart, actualTemp.attributeTypeStart); - assertEquals(expectedTemp.attributeTypeEnd, actualTemp.attributeTypeEnd); - assertEquals(expectedTemp.attributeValueStart, actualTemp.attributeValueStart); - assertEquals(expectedTemp.attributeValueEnd, actualTemp.attributeValueEnd); - assertEquals(expectedTemp.unrecognizedStart, actualTemp.unrecognizedStart); - assertEquals(expectedTemp.unrecognizedEnd, actualTemp.unrecognizedEnd); + assertEquals(expectedTemp.elementName, actualTemp.elementName); + assertEquals(expectedTemp.attributeName, actualTemp.attributeName); + assertEquals(expectedTemp.attributeType, actualTemp.attributeType); + assertEquals(expectedTemp.attributeValue, actualTemp.attributeValue); + assertEquals(expectedTemp.unrecognized, actualTemp.unrecognized); ArrayList expectedInternalChildren = expectedTemp.getInternalChildren(); ArrayList actualInternalChildren = actualTemp.getInternalChildren(); @@ -1037,72 +1007,52 @@ private static void compareTrees(DOMNode expectedNode, DOMNode actualNode) { assertEquals(true, actualNode.isDTDElementDecl()); DTDElementDecl expectedTemp = (DTDElementDecl) expectedNode; DTDElementDecl actualTemp = (DTDElementDecl) actualNode; - assertEquals(expectedTemp.nameStart, actualTemp.nameStart); - assertEquals(expectedTemp.nameEnd, actualTemp.nameEnd); - assertEquals(expectedTemp.categoryStart, actualTemp.categoryStart); - assertEquals(expectedTemp.categoryEnd, actualTemp.categoryEnd); - assertEquals(expectedTemp.contentStart, actualTemp.contentStart); - assertEquals(expectedTemp.contentEnd, actualTemp.contentEnd); - assertEquals(expectedTemp.unrecognizedStart, actualTemp.unrecognizedStart); - assertEquals(expectedTemp.unrecognizedEnd, actualTemp.unrecognizedEnd); + assertEquals(expectedTemp.name, actualTemp.name); + assertEquals(expectedTemp.category, actualTemp.category); + assertEquals(expectedTemp.content, actualTemp.content); + assertEquals(expectedTemp.unrecognized, actualTemp.unrecognized); } else if(expectedNode.isDTDEntityDecl()) { assertEquals(true, actualNode.isDTDEntityDecl()); DTDEntityDecl expectedTemp = (DTDEntityDecl) expectedNode; DTDEntityDecl actualTemp = (DTDEntityDecl) actualNode; - assertEquals(expectedTemp.nameStart, actualTemp.nameStart); - assertEquals(expectedTemp.nameEnd, actualTemp.nameEnd); - assertEquals(expectedTemp.valueStart, actualTemp.valueStart); - assertEquals(expectedTemp.valueEnd, actualTemp.valueEnd); - assertEquals(expectedTemp.kindStart, actualTemp.kindStart); - assertEquals(expectedTemp.kindEnd, actualTemp.kindEnd); - assertEquals(expectedTemp.publicIdStart, actualTemp.publicIdStart); - assertEquals(expectedTemp.publicIdEnd, actualTemp.publicIdEnd); - assertEquals(expectedTemp.systemIdStart, actualTemp.systemIdStart); - assertEquals(expectedTemp.systemIdEnd, actualTemp.systemIdEnd); - assertEquals(expectedTemp.unrecognizedStart, actualTemp.unrecognizedStart); - assertEquals(expectedTemp.unrecognizedEnd, actualTemp.unrecognizedEnd); + assertEquals(expectedTemp.name, actualTemp.name); + assertEquals(expectedTemp.value, actualTemp.value); + assertEquals(expectedTemp.kind, actualTemp.kind); + assertEquals(expectedTemp.publicId, actualTemp.publicId); + assertEquals(expectedTemp.systemId, actualTemp.systemId); + assertEquals(expectedTemp.unrecognized, actualTemp.unrecognized); } else if(expectedNode.isDTDNotationDecl()) { assertEquals(true, actualNode.isDTDNotationDecl()); DTDNotationDecl expectedTemp = (DTDNotationDecl) expectedNode; DTDNotationDecl actualTemp = (DTDNotationDecl) actualNode; - assertEquals(expectedTemp.nameStart, actualTemp.nameStart); - assertEquals(expectedTemp.nameEnd, actualTemp.nameEnd); - assertEquals(expectedTemp.kindStart, actualTemp.kindStart); - assertEquals(expectedTemp.kindEnd, actualTemp.kindEnd); - assertEquals(expectedTemp.publicIdStart, actualTemp.publicIdStart); - assertEquals(expectedTemp.publicIdEnd, actualTemp.publicIdEnd); - assertEquals(expectedTemp.systemIdStart, actualTemp.systemIdStart); - assertEquals(expectedTemp.systemIdEnd, actualTemp.systemIdEnd); - assertEquals(expectedTemp.unrecognizedStart, actualTemp.unrecognizedStart); - assertEquals(expectedTemp.unrecognizedEnd, actualTemp.unrecognizedEnd); + assertEquals(expectedTemp.name, actualTemp.name); + assertEquals(expectedTemp.kind, actualTemp.kind); + assertEquals(expectedTemp.publicId, actualTemp.publicId); + assertEquals(expectedTemp.systemId, actualTemp.systemId); + assertEquals(expectedTemp.unrecognized, actualTemp.unrecognized); } else if(expectedNode.isDoctype()) { assertEquals(true, actualNode.isDoctype()); DOMDocumentType expectedTemp = (DOMDocumentType) expectedNode; DOMDocumentType actualTemp = (DOMDocumentType) actualNode; - assertEquals(expectedTemp.nameStart, actualTemp.nameStart); - assertEquals(expectedTemp.nameEnd, actualTemp.nameEnd); - assertEquals(expectedTemp.kindStart, actualTemp.kindStart); - assertEquals(expectedTemp.kindEnd, actualTemp.kindEnd); - assertEquals(expectedTemp.publicIdStart, actualTemp.publicIdStart); - assertEquals(expectedTemp.publicIdEnd, actualTemp.publicIdEnd); - assertEquals(expectedTemp.systemIdStart, actualTemp.systemIdStart); - assertEquals(expectedTemp.systemIdEnd, actualTemp.systemIdEnd); - assertEquals(expectedTemp.internalSubsetStart, actualTemp.internalSubsetStart); - assertEquals(expectedTemp.internalSubsetEnd, actualTemp.internalSubsetEnd); + assertEquals(expectedTemp.name, actualTemp.name); + assertEquals(expectedTemp.kind, actualTemp.kind); + assertEquals(expectedTemp.publicId, actualTemp.publicId); + assertEquals(expectedTemp.systemId, actualTemp.systemId); + assertEquals(expectedTemp.internalSubset, actualTemp.internalSubset); } else if(expectedNode.isGenericDTDDecl()) { DTDDeclNode expectedTemp = (DTDDeclNode) expectedNode; DTDDeclNode actualTemp = (DTDDeclNode) actualNode; - assertEquals(expectedTemp.unrecognizedStart, actualTemp.unrecognizedStart); - assertEquals(expectedTemp.unrecognizedEnd, actualTemp.unrecognizedEnd); + assertEquals(expectedTemp.unrecognized.start, actualTemp.unrecognized.start); + assertEquals(expectedTemp.unrecognized.end, actualTemp.unrecognized.end); } assertEquals(expectedNode.isClosed(), actualNode.isClosed()); @@ -1117,25 +1067,13 @@ else if(expectedNode.isGenericDTDDecl()) { } public static void assertInternalAttlist(DTDAttlistDecl expected, DTDAttlistDecl actual) { - assertEquals(expected.attributeNameStart, actual.attributeNameStart); - assertEquals(expected.attributeNameEnd, actual.attributeNameEnd); - assertEquals(expected.attributeTypeStart, actual.attributeTypeStart); - assertEquals(expected.attributeTypeEnd, actual.attributeTypeEnd); - assertEquals(expected.attributeValueStart, actual.attributeValueStart); - assertEquals(expected.attributeValueEnd, actual.attributeValueEnd); - } - - public static void assertInternalNotation(DTDNotationDecl expected, DTDNotationDecl actual) { - assertEquals(expected.nameStart, actual.nameStart); - assertEquals(expected.nameEnd, actual.nameEnd); - assertEquals(expected.kindStart, actual.kindStart); - assertEquals(expected.kindEnd, actual.kindEnd); - assertEquals(expected.publicIdStart, actual.publicIdStart); - assertEquals(expected.publicIdEnd, actual.publicIdEnd); - assertEquals(expected.systemIdStart, actual.systemIdStart); - assertEquals(expected.systemIdEnd, actual.systemIdEnd); + assertEquals(expected.elementName, actual.elementName); + assertEquals(expected.attributeName, actual.attributeName); + assertEquals(expected.attributeType, actual.attributeType); + assertEquals(expected.attributeValue, actual.attributeValue); } + public void insertIntoAttributes(DOMNode n, String key, String value) { n.setAttribute(key, value); } diff --git a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/parser/XMLScannerForExternalDTDTest.java b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/parser/XMLScannerForExternalDTDTest.java index fb9857c005..233aa8bca3 100644 --- a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/parser/XMLScannerForExternalDTDTest.java +++ b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/dom/parser/XMLScannerForExternalDTDTest.java @@ -723,6 +723,39 @@ public void dtdUnrecognizedContent() { assertOffsetAndToken(31, TokenType.DTDEndTag); assertOffsetAndToken(32, TokenType.EOS); } + + @Test + public void dtdUnrecognizedContent2() { + String dtd = + "\r\n" + + "]]>\r\n" + + "\r\n" + + ""; + + scanner = XMLScanner.createScanner(dtd, true); + + assertOffsetAndToken(0, TokenType.Content); + + assertOffsetAndToken(23, TokenType.DTDStartEntity); + assertOffsetAndToken(31, TokenType.Whitespace); + assertOffsetAndToken(32, TokenType.DTDEntityPercent); + assertOffsetAndToken(33, TokenType.Whitespace); + assertOffsetAndToken(34, TokenType.DTDEntityName); + assertOffsetAndToken(42, TokenType.Whitespace); + assertOffsetAndToken(45, TokenType.DTDEntityValue); + assertOffsetAndToken(87, TokenType.Whitespace); + assertOffsetAndToken(91, TokenType.DTDEndTag); + + assertOffsetAndToken(92, TokenType.Content); // " ... ]]> ..." + + assertOffsetAndToken(101, TokenType.StartCommentTag); + assertOffsetAndToken(105, TokenType.Comment); + assertOffsetAndToken(175, TokenType.EndCommentTag); + assertOffsetAndToken(178, TokenType.EOS); + } public void assertOffsetAndToken(int tokenOffset, TokenType tokenType) { TokenType token = scanner.scan(); diff --git a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/contentmodel/DTDDiagnosticsTest.java b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/contentmodel/DTDDiagnosticsTest.java index 348659c7e5..9a04ddf1d4 100644 --- a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/contentmodel/DTDDiagnosticsTest.java +++ b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/contentmodel/DTDDiagnosticsTest.java @@ -71,7 +71,7 @@ public void MSG_ATTRIBUTE_NOT_DECLARED() throws Exception { " Reminder\r\n" + // " Don't forget me this weekend\r\n" + // " "; - XMLAssert.testDiagnosticsFor(xml, d(10, 10, 14, DTDErrorCode.MSG_ATTRIBUTE_NOT_DECLARED)); + XMLAssert.testDiagnosticsFor(xml, d(10, 15, 17, DTDErrorCode.MSG_ATTRIBUTE_NOT_DECLARED)); } @Test diff --git a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/contentmodel/DTDDoctypeDiagnosticsTest.java b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/contentmodel/DTDDoctypeDiagnosticsTest.java index 09ef3b4891..0ea6b03eac 100644 --- a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/contentmodel/DTDDoctypeDiagnosticsTest.java +++ b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/extensions/contentmodel/DTDDoctypeDiagnosticsTest.java @@ -29,7 +29,7 @@ public void MSG_ELEMENT_TYPE_REQUIRED_IN_ELEMENTDECL() throws Exception { " \r\n" + // ""; - XMLAssert.testDiagnosticsFor(xml, d(2, 2, 11, DTDErrorCode.MSG_ELEMENT_TYPE_REQUIRED_IN_ELEMENTDECL)); + XMLAssert.testDiagnosticsFor(xml, d(2, 4, 11, DTDErrorCode.MSG_ELEMENT_TYPE_REQUIRED_IN_ELEMENTDECL)); } @Test @@ -40,7 +40,7 @@ public void ElementDeclUnterminated() throws Exception { " \r\n" + // ""; - XMLAssert.testDiagnosticsFor(xml, d(3, 2, 30, DTDErrorCode.ElementDeclUnterminated)); + XMLAssert.testDiagnosticsFor(xml, d(3, 29, 30, DTDErrorCode.ElementDeclUnterminated)); } @Test @@ -51,7 +51,7 @@ public void MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN() throws Excepti "]>\r\n" + // ""; XMLAssert.testDiagnosticsFor(xml, - d(2, 2, 20, DTDErrorCode.MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN)); + d(2, 19, 20, DTDErrorCode.MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN)); } } diff --git a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/services/XMLDocumentSymbolsTest.java b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/services/XMLDocumentSymbolsTest.java index a337de5528..36bf4bfb6f 100644 --- a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/services/XMLDocumentSymbolsTest.java +++ b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/services/XMLDocumentSymbolsTest.java @@ -61,6 +61,5 @@ public void internalDTD() { ds("Email", SymbolKind.Property, r(8, 1, 8, 27), r(8, 1, 8, 27), null, Collections.emptyList()) // )), // ds("Folks", SymbolKind.Field, r(10, 0, 12, 8), r(10, 0, 12, 8), null, Collections.emptyList())); - } } diff --git a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/services/XMLFormatterTest.java b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/services/XMLFormatterTest.java index 239ddc29f9..dac899c30b 100644 --- a/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/services/XMLFormatterTest.java +++ b/org.eclipse.lsp4xml/src/test/java/org/eclipse/lsp4xml/services/XMLFormatterTest.java @@ -724,6 +724,600 @@ public void testContentFormatting6() throws BadLocationException { ""; format(content, expected, formattingOptions); } + + @Test public void testDoctypeNoInternalSubset() throws BadLocationException { + XMLFormattingOptions formattingOptions = createDefaultFormattingOptions(); + + String content = + "\r\n" + + "\r\n" + + " Fred\r\n" + + "\r\n" + + " Jani\r\n" + + "\r\n" + + " Reminder\r\n" + + " \r\n" + + " Don't forget me this weekend\r\n" + + ""; + String expected = + "\r\n" + + "\r\n" + + " Fred\r\n" + + " Jani\r\n" + + " Reminder\r\n" + + " Don't forget me this weekend\r\n" + + ""; + format(content, expected, formattingOptions); + } + + @Test public void testDoctypeInternalSubset() throws BadLocationException { + XMLFormattingOptions formattingOptions = createDefaultFormattingOptions(); + + String content = + "\r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + "]>\r\n" + + "\r\n" + + " Fred\r\n" + + "\r\n" + + "\r\n" + + " Jani\r\n" + + " \r\n" + + " Reminder\r\n" + + " Don't forget me this weekend\r\n" + + ""; + String expected = + "\r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + "]>\r\n" + + "\r\n" + + " Fred\r\n" + + " Jani\r\n" + + " Reminder\r\n" + + " Don't forget me this weekend\r\n" + + ""; + format(content, expected, formattingOptions); + } + + @Test public void testDoctypeInternalDeclSpacesBetweenParameters() throws BadLocationException { + XMLFormattingOptions formattingOptions = createDefaultFormattingOptions(); + + String content = + "\r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + "]>\r\n" + + "\r\n" + + " Fred\r\n" + + " Jani\r\n" + + " Reminder\r\n" + + " Don't forget me this weekend\r\n" + + " "; + String expected = + "\r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + "]>\r\n" + + "\r\n" + + " Fred\r\n" + + " Jani\r\n" + + " Reminder\r\n" + + " Don't forget me this weekend\r\n" + + ""; + format(content, expected, formattingOptions); + } + + @Test public void testDoctypeInternalWithAttlist() throws BadLocationException { + XMLFormattingOptions formattingOptions = createDefaultFormattingOptions(); + + String content = + "\r\n" + + "\r\n" + + " \r\n" + + "\r\n" + + " \r\n" + + "\r\n" + + "]>\r\n" + + "\r\n" + + "\r\n" + + " \r\n" + + " Fred\r\n" + + ""; + String expected = + "\r\n" + + " \r\n" + + " \r\n" + + "]>\r\n" + + "\r\n" + + " Fred\r\n" + + ""; + format(content, expected, formattingOptions); + } + + @Test public void testDoctypeInternalAllDecls() throws BadLocationException { + XMLFormattingOptions formattingOptions = createDefaultFormattingOptions(); + + String content = + "\r\n" + + "\r\n" + + " \r\n" + + "\r\n" + + " \r\n" + + "\r\n" + + " \r\n" + + "]>\r\n" + + ""; + String expected = + "\r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + "]>\r\n" + + ""; + format(content, expected, formattingOptions); + } + + @Test public void testDoctypeInternalWithComments() throws BadLocationException { + XMLFormattingOptions formattingOptions = createDefaultFormattingOptions(); + + String content = + "\r\n" + + "\r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + "]>\r\n" + + ""; + String expected = + "\r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + "]>\r\n" + + ""; + format(content, expected, formattingOptions); + } + + @Test public void testDoctypeInternalWithText() throws BadLocationException { + XMLFormattingOptions formattingOptions = createDefaultFormattingOptions(); + + String content = + "\r\n" + + "\r\n" + + "\r\n" + + " garbageazg df\r\n" + + " gdf\r\n" + + "garbageazgdfg\r\n" + + " df\r\n" + + " gd\r\n" + + "\r\n" + + "\r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + "]>"; + String expected = + "\r\n" + + " garbageazg df\r\n" + + " gdf\r\n" + + "garbageazgdfg\r\n" + + " df\r\n" + + " gd\r\n" + + " \r\n" + + "]>\r\n"; + format(content, expected, formattingOptions); + } + + @Test public void testDTDMultiParameterAttlist() throws BadLocationException { + XMLFormattingOptions formattingOptions = createDefaultFormattingOptions(); + + String content = + "\r\n"; + String expected = + ""; + format(content, expected, formattingOptions, "test.dtd"); + } + + @Test public void testDTDIndentation() throws BadLocationException { + XMLFormattingOptions formattingOptions = createDefaultFormattingOptions(); + + String content = + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " "; + String expected = + "\r\n" + + "\r\n" + + "\r\n" + + ""; + format(content, expected, formattingOptions, "test.dtd"); + } + + @Test public void testDTDNotEndBrackets() throws BadLocationException { + XMLFormattingOptions formattingOptions = createDefaultFormattingOptions(); + + String content = + "\r\n" + + "\r\n" + + "\r\n" + + " \r\n" + + "\r\n" + + " asdasd\r\n" + + " asd\r\n" + + "\r\n" + + "\r\n" + + "\r\n" + + ""; + String expected = + "\r\n" + + "\r\n" + + "asdasd\r\n" + + " asd\r\n" + + "\r\n" + + "\r\n" + + ""; + format(content, expected, formattingOptions, "test.dtd"); + } + + @Test public void testAllDoctypeParameters() throws BadLocationException { + XMLFormattingOptions formattingOptions = createDefaultFormattingOptions(); + + String content = + "\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" + + " sdsd\r\n" + + "\r\n" + + " \r\n" + + " \r\n" + + " er\r\n" + + " dd\r\n" + + " \r\n" + + ""; + String expected = + "\r\n" + + "\r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + "]>\r\n" + + "\r\n" + + " sdsd\r\n" + + " \r\n" + + " er\r\n" + + " dd\r\n" + + " \r\n" + + ""; + format(content, expected, formattingOptions); + } + + @Test public void testDTDElementContentWithAsterisk() throws BadLocationException { + XMLFormattingOptions formattingOptions = createDefaultFormattingOptions(); + + String content = + ""; + String expected = + ""; + format(content, expected, formattingOptions, "test.dtd", false); + } + + @Test public void testDoctypeSingleLineFormat() throws BadLocationException { + XMLFormattingOptions formattingOptions = createDefaultFormattingOptions(); + + String content = + "]>\r\n" + + ""; + String expected = + "\r\n" + + " \r\n" + + "]>\r\n" + + ""; + format(content, expected, formattingOptions); + } + + @Test public void testDoctypeInvalidParameter() throws BadLocationException { + XMLFormattingOptions formattingOptions = createDefaultFormattingOptions(); + + String content = + "\r\n" + + " \r\n" + + "]>"; + String expected = + "\r\n" + + " \r\n" + + "]>\r\n"; + format(content, expected, formattingOptions); + } + + @Test public void testDoctypeInvalidParameterUnclosed() throws BadLocationException { + XMLFormattingOptions formattingOptions = createDefaultFormattingOptions(); + + String content = + "\r\n" + + " \r\n" + + "]\r\n" + + "\r\n" + + "\r\n" + + ""; + String expected = + "\r\n" + + " \r\n" + + "]\r\n" + + ""; + format(content, expected, formattingOptions); + } + + @Test + public void testUnclosedSystemId() throws BadLocationException { + XMLFormattingOptions formattingOptions = createDefaultFormattingOptions(); + + String content = + "\r\n" + + "\r\n" + + " \r\n" + + "]>\r\n" + + "\r\n" + + ""; + String expected = + "\r\n" + + "\r\n" + + " \r\n" + + "]>\r\n" + + ""; + format(content, expected, formattingOptions); + } + + @Test + public void testUnclosedPublicId() throws BadLocationException { + XMLFormattingOptions formattingOptions = createDefaultFormattingOptions(); + + String content = + "\r\n" + + "\r\n" + + " \r\n" + + "]>\r\n" + + "\r\n" + + ""; + String expected = + "\r\n" + + "\r\n" + + " \r\n" + + "]>\r\n" + + ""; + format(content, expected, formattingOptions); + } + + @Test + public void testCommentAfterMissingClosingBracket() throws BadLocationException { + XMLFormattingOptions formattingOptions = createDefaultFormattingOptions(); + + String content = + "\r\n" + + "]>\r\n" + + "\r\n" + + ""; + String expected = + "\r\n" + + "]>\r\n" + + ""; + format(content, expected, formattingOptions); + } + + @Test + public void testHTMLDTD() throws BadLocationException { + XMLFormattingOptions formattingOptions = createDefaultFormattingOptions(); + + String content = + "\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" + + "%HTML4.dtd;"; + String expected = + "\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" + + "%HTML4.dtd;"; + format(content, expected, formattingOptions, "test.dtd"); + } + + @Test + public void testXMLInDTDFile() throws BadLocationException { + XMLFormattingOptions formattingOptions = createDefaultFormattingOptions(); + + String content = + "\r\n" + + "\r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + " \r\n" + + ""; + String expected = + "\r\n" + + "\r\n" + + "\r\n" + + "\r\n" + + "\r\n" + + "\r\n" + + ""; + format(content, expected, formattingOptions, "test.dtd"); + } + + @Test + public void testBadDTDFile() throws BadLocationException { + XMLFormattingOptions formattingOptions = createDefaultFormattingOptions(); + + String content = + "\r\n" + + "\r\n" + + "]]>\r\n" + + "\r\n" + + ""; + String expected = + "\r\n" + + "]]>\r\n" + + ""; + format(content, expected, formattingOptions, "test.dtd"); + } + + @Test + public void testIncompleteAttlistInternalDecl() throws BadLocationException { + XMLFormattingOptions formattingOptions = createDefaultFormattingOptions(); + + String content = + "\r\n" + + "\r\n" + + ""; + String expected = + "\r\n" + + ""; + format(content, expected, formattingOptions, "test.dtd"); + } + + + @Test + public void testTemplate() throws BadLocationException { + XMLFormattingOptions formattingOptions = createDefaultFormattingOptions(); + + String content = + ""; + String expected = + ""; + format(content, expected, formattingOptions); + } + + //-------------------------Tools----------------------------------------- @@ -733,10 +1327,20 @@ private static void format(String unformatted, String actual) throws BadLocation private static void format(String unformatted, String expected, XMLFormattingOptions formattingOptions) throws BadLocationException { + format(unformatted, expected, formattingOptions, "test://test.html"); + } + + private static void format(String unformatted, String expected, XMLFormattingOptions formattingOptions, String uri) + throws BadLocationException { + format(unformatted, expected, formattingOptions, uri, true); + } + + private static void format(String unformatted, String expected, XMLFormattingOptions formattingOptions, String uri, Boolean considerRangeFormat) + throws BadLocationException { + Range range = null; - String uri = "test://test.html"; - int rangeStart = unformatted.indexOf('|'); - int rangeEnd = unformatted.lastIndexOf('|'); + int rangeStart = considerRangeFormat ? unformatted.indexOf('|') : -1; + int rangeEnd = considerRangeFormat ? unformatted.lastIndexOf('|') : -1; if (rangeStart != -1 && rangeEnd != -1) { // remove '|' unformatted = unformatted.substring(0, rangeStart) + unformatted.substring(rangeStart + 1, rangeEnd) @@ -756,8 +1360,11 @@ private static void format(String unformatted, String expected, XMLFormattingOpt + unformatted.substring(rangeEnd - 1, unformatted.length()); } Assert.assertEquals(expected, formatted); + } + + private static XMLFormattingOptions createDefaultFormattingOptions() { return new XMLFormattingOptions(2, true); }