-
Notifications
You must be signed in to change notification settings - Fork 93
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support joinCDATALines setting with experimental formatter
Signed-off-by: Jessica He <jhe@redhat.com>
- Loading branch information
1 parent
de9c702
commit 0dad3b2
Showing
4 changed files
with
288 additions
and
48 deletions.
There are no files selected for viewing
112 changes: 112 additions & 0 deletions
112
org.eclipse.lemminx/src/main/java/org/eclipse/lemminx/services/format/DOMCDATAFormatter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2022 Red Hat Inc. and others. | ||
* All rights reserved. This program and the accompanying materials | ||
* which accompanies this distribution, and is available at | ||
* http://www.eclipse.org/legal/epl-v20.html | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
* | ||
* Contributors: | ||
* Red Hat Inc. - initial API and implementation | ||
*******************************************************************************/ | ||
package org.eclipse.lemminx.services.format; | ||
|
||
import java.util.List; | ||
|
||
import org.eclipse.lemminx.dom.DOMCDATASection; | ||
import org.eclipse.lsp4j.TextEdit; | ||
|
||
/** | ||
* DOM CDATA section formatter. | ||
*/ | ||
public class DOMCDATAFormatter { | ||
private final XMLFormatterDocumentNew formatterDocument; | ||
|
||
public DOMCDATAFormatter(XMLFormatterDocumentNew formatterDocument) { | ||
this.formatterDocument = formatterDocument; | ||
} | ||
|
||
public void formatCDATASection(DOMCDATASection cDATANode, XMLFormattingConstraints parentConstraints, | ||
List<TextEdit> edits) { | ||
|
||
String text = formatterDocument.getText(); | ||
int availableLineWidth = parentConstraints.getAvailableLineWidth(); | ||
int start = cDATANode.getStart(); | ||
int leftWhitespaceOffset = start > 0 ? start - 1 : 0; | ||
int spaceStart = -1; | ||
int spaceEnd = -1; | ||
|
||
while (leftWhitespaceOffset > 0 && Character.isWhitespace(text.charAt(leftWhitespaceOffset))) { | ||
leftWhitespaceOffset--; | ||
} | ||
|
||
if (isJoinCDATALines()) { | ||
int contentEnd = -1; | ||
int cDATAStartContent = cDATANode.getStartContent(); | ||
int cDATAEndContent = cDATANode.getEndContent(); | ||
for (int i = cDATAStartContent; i <= cDATAEndContent; i++) { | ||
char c = text.charAt(i); | ||
if (Character.isWhitespace(c)) { | ||
// Whitespaces | ||
if (spaceStart == -1) { | ||
spaceStart = i; | ||
} else { | ||
spaceEnd = i; | ||
} | ||
} else { | ||
int contentStart = i; | ||
while (i < cDATAEndContent && !Character.isWhitespace(text.charAt(i + 1))) { | ||
i++; | ||
} | ||
contentEnd = i; | ||
availableLineWidth -= (contentEnd + 1 - contentStart); | ||
if (availableLineWidth <= 0) { | ||
if (spaceStart != -1) { | ||
// Add new line when the comment extends over the maximum line width | ||
replaceLeftSpacesWithIndentation(parentConstraints.getIndentLevel(), contentStart, | ||
true, edits); | ||
int indentSpaces = (getTabSize() * parentConstraints.getIndentLevel()); | ||
availableLineWidth = getMaxLineWidth() - indentSpaces - (contentEnd + 1 - contentStart); | ||
} | ||
} else if (spaceStart == cDATAStartContent || contentEnd == cDATAEndContent) { | ||
// Remove spaces before and after the start and ending bracket of content | ||
removeLeftSpaces(spaceStart + 1, contentStart, edits); | ||
spaceStart = -1; | ||
spaceEnd = -1; | ||
} else { | ||
// Normalize space between content | ||
replaceSpacesWithOneSpace(spaceStart, spaceEnd, edits); | ||
availableLineWidth--; | ||
spaceStart = -1; | ||
spaceEnd = -1; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
private void removeLeftSpaces(int from, int to, List<TextEdit> edits) { | ||
formatterDocument.removeLeftSpaces(from, to, edits); | ||
} | ||
|
||
private boolean isJoinCDATALines() { | ||
return formatterDocument.getSharedSettings().getFormattingSettings().isJoinCDATALines(); | ||
} | ||
|
||
private int getTabSize() { | ||
return formatterDocument.getSharedSettings().getFormattingSettings().getTabSize(); | ||
} | ||
|
||
private int getMaxLineWidth() { | ||
return formatterDocument.getMaxLineWidth(); | ||
} | ||
|
||
private void replaceSpacesWithOneSpace(int spaceStart, int spaceEnd, List<TextEdit> edits) { | ||
formatterDocument.replaceSpacesWithOneSpace(spaceStart, spaceEnd, edits); | ||
} | ||
|
||
private int replaceLeftSpacesWithIndentation(int indentLevel, int offset, boolean addLineSeparator, | ||
List<TextEdit> edits) { | ||
return formatterDocument.replaceLeftSpacesWithIndentation(indentLevel, offset, addLineSeparator, edits); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
166 changes: 166 additions & 0 deletions
166
...java/org/eclipse/lemminx/services/format/experimental/XMLFormatterJoinCDATALinesTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2022 Red Hat Inc. and others. | ||
* All rights reserved. This program and the accompanying materials | ||
* which accompanies this distribution, and is available at | ||
* http://www.eclipse.org/legal/epl-v20.html | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
* | ||
* Contributors: | ||
* Red Hat Inc. - initial API and implementation | ||
*******************************************************************************/ | ||
package org.eclipse.lemminx.services.format.experimental; | ||
|
||
import static org.eclipse.lemminx.XMLAssert.te; | ||
|
||
import org.eclipse.lemminx.XMLAssert; | ||
import org.eclipse.lemminx.commons.BadLocationException; | ||
import org.eclipse.lemminx.settings.SharedSettings; | ||
import org.eclipse.lsp4j.TextEdit; | ||
import org.junit.jupiter.api.Test; | ||
|
||
/** | ||
* XML experimental formatter services tests with join CDATA lines setting. | ||
* | ||
*/ | ||
public class XMLFormatterJoinCDATALinesTest { | ||
|
||
@Test | ||
public void testCDATANotClosed() throws BadLocationException { | ||
String content = "<foo>\r\n" + // | ||
"<![CDATA[ \r\n" + // | ||
"</foo>"; | ||
SharedSettings settings = new SharedSettings(); | ||
String expected = content; | ||
assertFormat(content, expected, settings); | ||
} | ||
|
||
@Test | ||
public void testCDATAWithRange() throws BadLocationException { | ||
String content = "<foo>\r\n" + // | ||
" <![CDATA[ |<bar>|\r\n" + // | ||
" </bar>\r\n" + // | ||
" ]]>\r\n" + // | ||
"</foo>"; | ||
String expected = "<foo>\r\n" + // | ||
" <![CDATA[ <bar>\r\n" + // | ||
" </bar>\r\n" + // | ||
" ]]>\r\n" + // | ||
"</foo>"; | ||
SharedSettings settings = new SharedSettings(); | ||
assertFormat(content, expected, settings); | ||
assertFormat(expected, expected, settings); | ||
} | ||
|
||
@Test | ||
public void testJoinCDATALinesSameLine() throws BadLocationException { | ||
String content = "<a> <![CDATA[\r\n" + // | ||
" < \r\n" + // | ||
"]]> </a>"; | ||
String expected = "<a> <![CDATA[<]]> </a>"; | ||
SharedSettings settings = new SharedSettings(); | ||
settings.getFormattingSettings().setJoinCDATALines(true); | ||
assertFormat(content, expected, settings, // | ||
te(0, 15, 1, 2, ""), // | ||
te(1, 3, 2, 0, "")); | ||
assertFormat(expected, expected, settings); | ||
} | ||
|
||
@Test | ||
public void testJoinCDATALinesEmpty() throws BadLocationException { | ||
String content = "<a> <![CDATA[\r\n" + // | ||
" \r\n" + // | ||
"]]> </a>"; | ||
String expected = "<a> <![CDATA[]]> </a>"; | ||
SharedSettings settings = new SharedSettings(); | ||
settings.getFormattingSettings().setJoinCDATALines(true); | ||
assertFormat(content, expected, settings, // | ||
te(0, 15, 2, 0, "")); | ||
assertFormat(expected, expected, settings); | ||
} | ||
|
||
// From issue: https://github.com/eclipse/lemminx/issues/1193 | ||
@Test | ||
public void testJoinCDATALinesWithText() throws BadLocationException { | ||
String content = "<a> x <![CDATA[\r\n" + // | ||
"<\r\n" + // | ||
"]]> y </a>"; | ||
String expected = "<a> x <![CDATA[<]]> y </a>"; | ||
SharedSettings settings = new SharedSettings(); | ||
settings.getFormattingSettings().setJoinCDATALines(true); | ||
assertFormat(content, expected, settings, // | ||
te(0, 3, 0, 5, " "), // | ||
te(0, 6, 0, 8, " "), // | ||
te(0, 17, 1, 0, ""), // | ||
te(1, 1, 2, 0, ""), // | ||
te(2, 5, 2, 7, " ")); | ||
assertFormat(expected, expected, settings); | ||
} | ||
|
||
@Test | ||
public void testJoinCDATALines() throws BadLocationException { | ||
String content = "<a>\r\n" + // | ||
"<![CDATA[\r\n" + // | ||
"line 1\r\n" + // | ||
"\r\n" + // | ||
"\r\n" + // | ||
"line 2\r\n" + // | ||
"line 3\r\n" + // | ||
"]]> </a>"; | ||
String expected = "<a>\r\n" + // | ||
"<![CDATA[line 1 line 2 line 3]]> </a>"; | ||
SharedSettings settings = new SharedSettings(); | ||
settings.getFormattingSettings().setJoinCDATALines(true); | ||
assertFormat(content, expected, settings, // | ||
te(1, 9, 2, 0, ""), // | ||
te(2, 6, 5, 0, " "), // | ||
te(5, 6, 6, 0, " "), // | ||
te(6, 6, 7, 0, "")); | ||
assertFormat(expected, expected, settings); | ||
} | ||
|
||
@Test | ||
public void testJoinCDATALinesMultiLine() throws BadLocationException { | ||
String content = "<a>\r\n" + // | ||
"<![CDATA[\r\n" + // | ||
"line 1\r\n" + // | ||
"\r\n" + // | ||
"\r\n" + // | ||
"line 2\r\n" + // | ||
"line 3 test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test test\r\n" | ||
+ // | ||
"]]> </a>"; | ||
String expected = "<a>\r\n" + // | ||
"<![CDATA[line 1 line 2 line 3 test test test test test test test test test test test\r\n" + // | ||
" test test test test test test test test test test test test test test test\r\n" + // | ||
" test test test test test test test test test]]> </a>"; | ||
SharedSettings settings = new SharedSettings(); | ||
settings.getFormattingSettings().setJoinCDATALines(true); | ||
assertFormat(content, expected, settings, // | ||
te(1, 9, 2, 0, ""), // | ||
te(2, 6, 5, 0, " "), // | ||
te(5, 6, 6, 0, " "), // | ||
te(6, 61, 6, 62, "\r\n "), // | ||
te(6, 136, 6, 137, "\r\n "), // | ||
te(6, 181, 7, 0, "")); | ||
assertFormat(expected, expected, settings); | ||
} | ||
|
||
|
||
private static void assertFormat(String unformatted, String expected, SharedSettings sharedSettings, | ||
TextEdit... expectedEdits) throws BadLocationException { | ||
assertFormat(unformatted, expected, sharedSettings, "test://test.html", expectedEdits); | ||
} | ||
|
||
private static void assertFormat(String unformatted, String expected, SharedSettings sharedSettings, String uri, | ||
TextEdit... expectedEdits) throws BadLocationException { | ||
assertFormat(unformatted, expected, sharedSettings, uri, true, expectedEdits); | ||
} | ||
|
||
private static void assertFormat(String unformatted, String expected, SharedSettings sharedSettings, String uri, | ||
Boolean considerRangeFormat, TextEdit... expectedEdits) throws BadLocationException { | ||
// Force to "experimental" formatter | ||
sharedSettings.getFormattingSettings().setExperimental(true); | ||
XMLAssert.assertFormat(null, unformatted, expected, sharedSettings, uri, considerRangeFormat, expectedEdits); | ||
} | ||
} |