diff --git a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/participants/DTDErrorCode.java b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/participants/DTDErrorCode.java index dffa147600..e486160dec 100644 --- a/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/participants/DTDErrorCode.java +++ b/org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/extensions/contentmodel/participants/DTDErrorCode.java @@ -24,6 +24,7 @@ import org.eclipse.lemminx.dom.DOMRange; import org.eclipse.lemminx.extensions.contentmodel.participants.codeactions.ElementDeclUnterminatedCodeAction; import org.eclipse.lemminx.extensions.contentmodel.participants.codeactions.EntityNotDeclaredCodeAction; +import org.eclipse.lemminx.extensions.contentmodel.participants.codeactions.FixMissingSpaceCodeAction; import org.eclipse.lemminx.extensions.contentmodel.participants.codeactions.dtd_not_foundCodeAction; import org.eclipse.lemminx.services.extensions.ICodeActionParticipant; import org.eclipse.lemminx.services.extensions.diagnostics.IXMLErrorCode; @@ -36,7 +37,7 @@ /** * DTD error code. - * + * * @see https://wiki.xmldation.com/Support/Validator * */ @@ -67,6 +68,9 @@ public enum DTDErrorCode implements IXMLErrorCode { MSG_NOTATION_NAME_REQUIRED_IN_NOTATIONDECL, // MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN, // MSG_REQUIRED_ATTRIBUTE_NOT_SPECIFIED, // + MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ATTLISTDECL, // + MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ELEMENTDECL, // + MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL, // MSG_SPACE_REQUIRED_AFTER_NOTATION_NAME_IN_NOTATIONDECL, // NotationDeclUnterminated, // OpenQuoteExpected, // @@ -110,7 +114,7 @@ public static DTDErrorCode get(String name) { /** * Create the LSP range from the SAX error. - * + * * @param location * @param key * @param arguments @@ -195,6 +199,13 @@ public static Range toLSPRange(XMLLocator location, DTDErrorCode code, Object[] case MSG_ELEMENT_TYPE_REQUIRED_IN_ELEMENTDECL: { return XMLPositionUtility.selectDTDDeclTagNameAt(offset, document); } + + case MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ATTLISTDECL: + case MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ELEMENTDECL: + case MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL: { + return XMLPositionUtility.selectDTDDeclTagNameAt(offset, document); + } + case dtd_not_found: { // Check if DTD location comes from a xml-model/@href String hrefLocation = (String) arguments[1]; @@ -220,5 +231,8 @@ public static void registerCodeActionParticipants(Map codeActions, + SharedSettings sharedSettings, IComponentProvider componentProvider) { + Range diagnosticRange = diagnostic.getRange(); + try { + int startOffset = document.offsetAt(diagnosticRange.getStart()); + int endOffset = document.offsetAt(diagnosticRange.getEnd()); + String text = document.getText(); + String value = text.substring(startOffset, endOffset); + codeActions.add(CodeActionFactory.insert("Add space after '" + value + "'", diagnosticRange.getEnd(), " ", + document.getTextDocument(), diagnostic)); + } catch (BadLocationException | IndexOutOfBoundsException e) { + codeActions.add(CodeActionFactory.insert("Add space", diagnosticRange.getEnd(), " ", + document.getTextDocument(), diagnostic)); + } + } + +} diff --git a/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/extensions/contentmodel/DTDDiagnosticsTest.java b/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/extensions/contentmodel/DTDDiagnosticsTest.java index a32ed2bbda..1cc1ea3efd 100644 --- a/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/extensions/contentmodel/DTDDiagnosticsTest.java +++ b/org.eclipse.lemminx/src/test/java/org/eclipse/lemminx/extensions/contentmodel/DTDDiagnosticsTest.java @@ -642,6 +642,73 @@ public void testDTDNotFoundWithPUBLIC() throws Exception { d(5, 4, 5, 21, XMLSyntaxErrorCode.ETagRequired)); // [4] } + @Test + public void MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ELEMENTDECL_DTD() throws Exception { + String xml = ""; + testDiagnosticsFor(xml, "test.dtd", d(0, 2, 9, DTDErrorCode.MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ELEMENTDECL)); + } + + @Test + public void MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ELEMENTDECL_INLINE_DOCTYPE() throws Exception { + String xml = "\n" + // + "]>"; + testDiagnosticsFor(xml, d(1, 4, 11, DTDErrorCode.MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ELEMENTDECL)); + } + + @Test + public void MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ELEMENTDECL_DTD_CLOSING_MISSING() throws Exception { + String xml = ""; + testDiagnosticsFor(xml, d(1, 4, 11, DTDErrorCode.MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ELEMENTDECL)); + } + + @Test + public void MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ATTLISTDECL() throws Exception { + String xml = ""; + Diagnostic diagnostic = d(1, 4, 11, DTDErrorCode.MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ELEMENTDECL); + testCodeActionsFor(xml, diagnostic, ca(diagnostic, te(1, 11, 1, 11, " "))); + } + + @Test + public void MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ATTLISTDECLCodeAction() throws Exception { + String xml = ""; + Diagnostic diagnostic = d(1, 4, 11, DTDErrorCode.MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ATTLISTDECL); + testCodeActionsFor(xml, diagnostic, ca(diagnostic, te(1, 11, 1, 11, " "))); + } + + @Test + public void MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECLCodeAction() throws Exception { + String xml = ""; + Diagnostic diagnostic = d(1, 4, 10, DTDErrorCode.MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL); + testCodeActionsFor(xml, diagnostic, ca(diagnostic, te(1, 10, 1, 10, " "))); + } + private static void testDiagnosticsFor(String xml, Diagnostic... expected) { XMLAssert.testDiagnosticsFor(xml, "src/test/resources/catalogs/catalog.xml", expected); } @@ -649,4 +716,8 @@ private static void testDiagnosticsFor(String xml, Diagnostic... expected) { private static void testPublicDiagnosticsFor(String xml, Diagnostic... expected) { XMLAssert.testDiagnosticsFor(xml, "src/test/resources/catalogs/catalog-public.xml", expected); } + + private static void testDiagnosticsFor(String xml, String fileURI, Diagnostic... expected) { + XMLAssert.testDiagnosticsFor(xml, "src/test/resources/catalogs/catalog.xml", null, fileURI, expected); + } }