Skip to content

Commit

Permalink
Support trimTrailingWhitespace setting with experimental formatter
Browse files Browse the repository at this point in the history
  • Loading branch information
JessicaJHee authored and datho7561 committed Nov 1, 2022
1 parent 3660f93 commit 6a49548
Show file tree
Hide file tree
Showing 8 changed files with 481 additions and 206 deletions.
Expand Up @@ -48,7 +48,8 @@ public void formatElement(DOMElement element, XMLFormattingConstraints parentCon

// Set indent level for text in mixed content
int mixedIndentLevel = parentConstraints.getMixedContentIndentLevel();
if (mixedIndentLevel == 0 && parentConstraints.getFormatElementCategory() == FormatElementCategory.MixedContent){
if (mixedIndentLevel == 0
&& parentConstraints.getFormatElementCategory() == FormatElementCategory.MixedContent) {
parentConstraints.setMixedContentIndentLevel(indentLevel);
}

Expand Down Expand Up @@ -77,12 +78,12 @@ private int formatStartTagElement(DOMElement element, XMLFormattingConstraints p
// ex : </
return element.getEnd() - element.getStart();
}
int width = 0;
int indentLevel = parentConstraints.getIndentLevel();
int width = element.getTagName() != null ? element.getTagName().length() + 1 : 0;
FormatElementCategory formatElementCategory = parentConstraints.getFormatElementCategory();
int startTagOpenOffset = element.getStartTagOpenOffset();
int startTagCloseOffset = element.getStartTagCloseOffset();
boolean addLineSeparator = element.getParentElement() == null && element.getPreviousSibling() == null;

if (end != -1 && startTagOpenOffset > end
|| start != -1 && startTagCloseOffset != -1 && startTagCloseOffset < start) {
return 0;
Expand All @@ -100,46 +101,27 @@ private int formatStartTagElement(DOMElement element, XMLFormattingConstraints p
if (parentStartCloseOffset != startTagOpenOffset
&& StringUtils.isWhitespace(formatterDocument.getText(), parentStartCloseOffset,
startTagOpenOffset)) {
int nbSpaces = replaceLeftSpacesWithIndentation(indentLevel, parentStartCloseOffset,
startTagOpenOffset, !addLineSeparator, edits);
width = element.getTagName() != null ? nbSpaces + element.getTagName().length() + 1 : nbSpaces;
if (!addLineSeparator) {
width -= formatterDocument.getLineDelimiter().length();
}
replaceLeftSpacesWithIndentationPreservedNewLines(parentStartCloseOffset, startTagOpenOffset,
indentLevel, edits);
}
width = element.getTagName() != null ? element.getTagName().length() + 1 : 0;
break;
case IgnoreSpace:
// If preserve new lines
int preservedNewLines = getPreservedNewlines();
int currentNewLineCount = XMLFormatterDocumentNew.getExistingNewLineCount(formatterDocument.getText(),
startTagOpenOffset, formatterDocument.getLineDelimiter());
if (element.getParentNode().isOwnerDocument() && element.getParentNode().getFirstChild() == element){
if (element.getParentNode().isOwnerDocument() && element.getParentNode().getFirstChild() == element) {
// If the element is at the start of the file, remove new lines and spaces
currentNewLineCount = 0;
}
if (currentNewLineCount > preservedNewLines) {
replaceLeftSpacesWithIndentationWithMultiNewLines(indentLevel, 0, startTagOpenOffset,
preservedNewLines + 1, edits);
} else {
int newLineCount = currentNewLineCount == 0 && !addLineSeparator ? 1 : currentNewLineCount;
int nbSpaces = replaceLeftSpacesWithIndentationWithMultiNewLines(indentLevel, 0, startTagOpenOffset,
newLineCount, edits);
width = element.getTagName() != null ? nbSpaces + element.getTagName().length() + 1 : nbSpaces;
if (!addLineSeparator) {
width -= formatterDocument.getLineDelimiter().length();
}
replaceLeftSpacesWithIndentation(indentLevel, 0, startTagOpenOffset, false, edits);
break;
}
replaceLeftSpacesWithIndentationPreservedNewLines(0, startTagOpenOffset,
indentLevel, edits);
width += indentLevel * getTabSize();
parentConstraints.setAvailableLineWidth(getMaxLineWidth());
break;
case NormalizeSpace:
width = element.getTagName() != null ? element.getTagName().length() + 1 : 0;
break;
}
parentConstraints.setAvailableLineWidth(parentConstraints.getAvailableLineWidth() - width);
if (formatElementCategory != FormatElementCategory.PreserveSpace) {
formatAttributes(element, parentConstraints, edits);

boolean formatted = false;
width = 0;
switch (emptyElements) {
Expand Down Expand Up @@ -301,8 +283,7 @@ private int formatEndTagElement(DOMElement element, XMLFormattingConstraints par
int endTagOffset = element.getEndTagOpenOffset();
int startTagCloseOffset = element.getStartTagCloseOffset();

int width = 0;
int nbSpaces = 0;
int width = element.getTagName() != null ? element.getTagName().length() + 2 : 0;

switch (formatElementCategory) {
case PreserveSpace:
Expand All @@ -315,29 +296,17 @@ private int formatEndTagElement(DOMElement element, XMLFormattingConstraints par
if ((element.getLastChild().isElement() || element.getLastChild().isComment())
&& Character.isWhitespace(formatterDocument.getText().charAt(endTagOffset - 1))
&& !isPreserveEmptyContent()) {
nbSpaces = replaceLeftSpacesWithIndentation(indentLevel, startTagCloseOffset, endTagOffset, true,
edits);
replaceLeftSpacesWithIndentationPreservedNewLines(startTagCloseOffset, endTagOffset,
indentLevel, edits);
}
width = element.getTagName() != null ? nbSpaces + element.getTagName().length() + 2 : nbSpaces;
width += indentLevel * getTabSize();
break;
case IgnoreSpace:
// If preserve new lines
int preservedNewLines = getPreservedNewlines();
int currentNewLineCount = XMLFormatterDocumentNew.getExistingNewLineCount(formatterDocument.getText(),
endTagOffset, formatterDocument.getLineDelimiter());
if (currentNewLineCount > preservedNewLines) {
replaceLeftSpacesWithIndentationWithMultiNewLines(indentLevel, startTagCloseOffset,
endTagOffset, preservedNewLines + 1, edits);
} else {
int newLineCount = currentNewLineCount == 0 ? 1 : currentNewLineCount;
replaceLeftSpacesWithIndentationWithMultiNewLines(indentLevel, startTagCloseOffset, endTagOffset,
newLineCount, edits);
nbSpaces = indentLevel * getTabSize();
width = element.getTagName() != null ? nbSpaces + element.getTagName().length() + 2 : nbSpaces;
break;
}
replaceLeftSpacesWithIndentationPreservedNewLines(startTagCloseOffset, endTagOffset,
indentLevel, edits);
width += indentLevel * getTabSize();
break;
case NormalizeSpace:
width = element.getTagName() != null ? element.getTagName().length() + 2 : 0;
break;
}
// 2) remove some spaces between the end tag and and close bracket
Expand Down Expand Up @@ -408,9 +377,9 @@ private int replaceLeftSpacesWithIndentation(int indentLevel, int from, int to,
return formatterDocument.replaceLeftSpacesWithIndentation(indentLevel, from, to, addLineSeparator, edits);
}

private int replaceLeftSpacesWithIndentationWithMultiNewLines(int indentLevel, int from, int to, int newLineCount,
List<TextEdit> edits) {
return formatterDocument.replaceLeftSpacesWithIndentationWithMultiNewLines(indentLevel, from, to, newLineCount,
private void replaceLeftSpacesWithIndentationPreservedNewLines(int spaceStart, int spaceEnd,
int indentLevel, List<TextEdit> edits) {
formatterDocument.replaceLeftSpacesWithIndentationPreservedNewLines(spaceStart, spaceEnd, indentLevel,
edits);
}

Expand Down Expand Up @@ -451,10 +420,6 @@ private static DOMAttr getLastAttribute(DOMElement element) {
return attributes.get(attributes.size() - 1);
}

private int getPreservedNewlines() {
return formatterDocument.getSharedSettings().getFormattingSettings().getPreservedNewlines();
}

private boolean isPreserveAttributeLineBreaks() {
return formatterDocument.getSharedSettings().getFormattingSettings().isPreserveAttributeLineBreaks();
}
Expand Down
Expand Up @@ -44,13 +44,17 @@ public void formatText(DOMText textNode, XMLFormattingConstraints parentConstrai

int spaceStart = -1;
int spaceEnd = -1;
int lineSeparatorOffset = -1;
boolean containsNewLine = false;

for (int i = textNode.getStart(); i < textNode.getEnd(); i++) {
char c = text.charAt(i);
if (Character.isWhitespace(c)) {
// Whitespaces...
if (isLineSeparator(c)) {
if (!containsNewLine) {
lineSeparatorOffset = i;
}
containsNewLine = true;
}
if (spaceStart == -1) {
Expand Down Expand Up @@ -91,7 +95,7 @@ public void formatText(DOMText textNode, XMLFormattingConstraints parentConstrai
replaceSpacesWithOneSpace(spaceStart, spaceEnd - 1, edits);
containsNewLine = false;
} else if (containsNewLine) {
replaceLeftSpacesWithIndentationPreservedNewLines(contentStart, spaceStart, spaceEnd,
replaceLeftSpacesWithIndentationPreservedNewLines(spaceStart, spaceEnd,
indentLevel, edits);
containsNewLine = false;
availableLineWidth = maxLineWidth - (contentEnd - contentStart)
Expand Down Expand Up @@ -124,24 +128,11 @@ public void formatText(DOMText textNode, XMLFormattingConstraints parentConstrai
// Decrement indent level if is mixed content and text content is the last child
indentLevel--;
}
replaceLeftSpacesWithIndentationPreservedNewLines(spaceEnd, spaceStart, spaceEnd + 1, indentLevel,
replaceLeftSpacesWithIndentationPreservedNewLines(spaceStart, spaceEnd + 1, indentLevel,
edits);
}
}
}

private void replaceLeftSpacesWithIndentationPreservedNewLines(int contentStart, int spaceStart, int spaceEnd,
int indentLevel, List<TextEdit> edits) {
int preservedNewLines = getPreservedNewlines();
int currentNewLineCount = XMLFormatterDocumentNew.getExistingNewLineCount(
formatterDocument.getText(), contentStart, formatterDocument.getLineDelimiter());
if (currentNewLineCount > preservedNewLines) {
replaceLeftSpacesWithIndentationWithMultiNewLines(indentLevel, spaceStart,
spaceEnd, preservedNewLines + 1, edits);
} else {
int newLineCount = currentNewLineCount == 0 ? 1 : currentNewLineCount;
replaceLeftSpacesWithIndentationWithMultiNewLines(indentLevel, spaceStart, spaceEnd,
newLineCount, edits);
} else if (isTrimTrailingWhitespace()) {
removeLeftSpaces(spaceStart, lineSeparatorOffset, edits);
}
}

Expand Down Expand Up @@ -170,17 +161,21 @@ private int replaceLeftSpacesWithIndentation(int indentLevel, int from, int to,
return formatterDocument.replaceLeftSpacesWithIndentation(indentLevel, from, to, addLineSeparator, edits);
}

private int replaceLeftSpacesWithIndentationWithMultiNewLines(int indentLevel, int from, int to, int newLineCount,
List<TextEdit> edits) {
return formatterDocument.replaceLeftSpacesWithIndentationWithMultiNewLines(indentLevel, from, to, newLineCount,
private void replaceLeftSpacesWithIndentationPreservedNewLines(int spaceStart, int spaceEnd,
int indentLevel, List<TextEdit> edits) {
formatterDocument.replaceLeftSpacesWithIndentationPreservedNewLines(spaceStart, spaceEnd, indentLevel,
edits);
}

private void removeLeftSpaces(int leftLimit, int to, List<TextEdit> edits) {
formatterDocument.replaceLeftSpacesWith(leftLimit, to, "", edits);
}

private boolean isJoinContentLines() {
return formatterDocument.getSharedSettings().getFormattingSettings().isJoinContentLines();
}

private int getPreservedNewlines() {
return formatterDocument.getSharedSettings().getFormattingSettings().getPreservedNewlines();
private boolean isTrimTrailingWhitespace() {
return formatterDocument.getSharedSettings().getFormattingSettings().isTrimTrailingWhitespace();
}
}
Expand Up @@ -12,7 +12,7 @@
package org.eclipse.lemminx.services.format;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
Expand Down Expand Up @@ -97,7 +97,7 @@ private static boolean isMatchExpectedContent(int from, int to, String expectedC

public static String applyEdits(TextDocument document, List<? extends TextEdit> edits) throws BadLocationException {
String text = document.getText();
List<? extends TextEdit> sortedEdits = mergeSort(edits /* .map(getWellformedEdit) */, (a, b) -> {
Collections.sort(edits /* .map(getWellformedEdit) */, (a, b) -> {
int diff = a.getRange().getStart().getLine() - b.getRange().getStart().getLine();
if (diff == 0) {
return a.getRange().getStart().getCharacter() - b.getRange().getStart().getCharacter();
Expand All @@ -106,7 +106,7 @@ public static String applyEdits(TextDocument document, List<? extends TextEdit>
});
int lastModifiedOffset = 0;
List<String> spans = new ArrayList<>();
for (TextEdit e : sortedEdits) {
for (TextEdit e : edits) {
int startOffset = document.offsetAt(e.getRange().getStart());
if (startOffset < lastModifiedOffset) {
throw new Error("Overlapping edit");
Expand All @@ -123,40 +123,6 @@ public static String applyEdits(TextDocument document, List<? extends TextEdit>
.collect(Collectors.joining());
}

private static <T> List<T> mergeSort(List<T> data, Comparator<T> comparator) {
if (data.size() <= 1) {
// sorted
return data;
}
int p = (data.size() / 2) | 0;
List<T> left = data.subList(0, p);
List<T> right = data.subList(p, data.size());

mergeSort(left, comparator);
mergeSort(right, comparator);

int leftIdx = 0;
int rightIdx = 0;
int i = 0;
while (leftIdx < left.size() && rightIdx < right.size()) {
int ret = comparator.compare(left.get(leftIdx), right.get(rightIdx));
if (ret <= 0) {
// smaller_equal -> take left to preserve order
data.set(i++, left.get(leftIdx++));
} else {
// greater -> take right
data.set(i++, right.get(rightIdx++));
}
}
while (leftIdx < left.size()) {
data.set(i++, left.get(leftIdx++));
}
while (rightIdx < right.size()) {
data.set(i++, right.get(rightIdx++));
}
return data;
}

/**
* Returns the offset of the first whitespace that's found in the given range
* [leftLimit,to] from the left of the to, and leftLimit otherwise.
Expand Down

0 comments on commit 6a49548

Please sign in to comment.