Cleanup trimming logic
This commit is contained in:
7 files changed
+92
-46
No files matched your search
@@ -436,7 +436,7 @@ final class ApexTreeBuilder extends AstVisitor<AdditionalPassScope> {
|
||||
if (checkForCommentSuppression && commentText.startsWith("//")) {
|
||||
Chars trimmed = commentText.subSequence("//".length(), commentText.length()).trimStart();
|
||||
if (trimmed.startsWith(suppressMarker)) {
|
||||
Chars userMessage = trimmed.subSequence(suppressMarker.length(), trimmed.length()).trim();
|
||||
Chars userMessage = trimmed.subSequence(suppressMarker.length()).trim();
|
||||
suppressMap.put(source.lineColumnAtOffset(startIdx).getLine(), userMessage.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import java.util.Iterator;
|
||||
|
||||
import net.sourceforge.pmd.PMD;
|
||||
import net.sourceforge.pmd.cpd.renderer.CPDRenderer;
|
||||
import net.sourceforge.pmd.lang.document.Chars;
|
||||
import net.sourceforge.pmd.util.StringUtil;
|
||||
|
||||
public class SimpleRenderer implements Renderer, CPDRenderer {
|
||||
@@ -49,8 +50,9 @@ public class SimpleRenderer implements Renderer, CPDRenderer {
|
||||
String source = match.getSourceCodeSlice();
|
||||
|
||||
if (trimLeadingWhitespace) {
|
||||
for (String line : StringUtil.linesWithTrimIndent(source)) {
|
||||
writer.append(line).append(PMD.EOL);
|
||||
for (Chars line : StringUtil.linesWithTrimIndent(source)) {
|
||||
line.writeFully(writer);
|
||||
writer.append(PMD.EOL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -363,6 +363,14 @@ public final class Chars implements CharSequence {
|
||||
return slice(start, end - start);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subsequence that starts at the given offset and ends
|
||||
* at the end of this string. Similar to {@link String#substring(int)}.
|
||||
*/
|
||||
public Chars subSequence(int start) {
|
||||
return slice(start, len - start);
|
||||
}
|
||||
|
||||
/**
|
||||
* Slice a region of text.
|
||||
*
|
||||
@@ -415,11 +423,11 @@ public final class Chars implements CharSequence {
|
||||
}
|
||||
|
||||
private static void validateRangeWithAssert(int off, int len, int bound) {
|
||||
assert len >= 0 && off >= 0 && (off + len) <= bound : invalidRange(off, len, bound);
|
||||
assert len >= 0 && off >= 0 && off + len <= bound : invalidRange(off, len, bound);
|
||||
}
|
||||
|
||||
private static void validateRange(int off, int len, int bound) {
|
||||
if (len < 0 || off < 0 || (off + len) > bound) {
|
||||
if (len < 0 || off < 0 || off + len > bound) {
|
||||
throw new IndexOutOfBoundsException(invalidRange(off, len, bound));
|
||||
}
|
||||
}
|
||||
@@ -429,7 +437,7 @@ public final class Chars implements CharSequence {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
public @NonNull String toString() {
|
||||
// this already avoids the copy if start == 0 && len == str.length()
|
||||
return str.substring(start, start + len);
|
||||
}
|
||||
@@ -548,7 +556,7 @@ public final class Chars implements CharSequence {
|
||||
private final int max = start + len;
|
||||
|
||||
@Override
|
||||
public int read(char[] cbuf, int off, int len) {
|
||||
public int read(char @NonNull [] cbuf, int off, int len) {
|
||||
if (len < 0 || off < 0 || off + len > cbuf.length) {
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ import org.pcollections.PSet;
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
import net.sourceforge.pmd.internal.util.AssertionUtil;
|
||||
import net.sourceforge.pmd.internal.util.IteratorUtil;
|
||||
import net.sourceforge.pmd.lang.document.Chars;
|
||||
|
||||
/**
|
||||
* Generic collection and array-related utility functions for java.util types.
|
||||
@@ -635,6 +636,16 @@ public final class CollectionUtil {
|
||||
return sb;
|
||||
}
|
||||
|
||||
public static @NonNull StringBuilder joinCharsIntoStringBuilder(List<Chars> lines, String delimiter) {
|
||||
return joinOn(
|
||||
new StringBuilder(),
|
||||
lines,
|
||||
(buf, line) -> line.appendChars(buf),
|
||||
delimiter
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Merge the second map into the first. If some keys are in common,
|
||||
* merge them using the merge function, like {@link Map#merge(Object, Object, BiFunction)}.
|
||||
|
||||
@@ -279,8 +279,7 @@ public final class StringUtil {
|
||||
* the left without misaligning them.
|
||||
*
|
||||
* <p>Note: the spec is described in
|
||||
* <a
|
||||
* href='https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/lang/String.html#stripIndent()'>String#stripIndent</a>
|
||||
* <a href='https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/lang/String.html#stripIndent()'>String#stripIndent</a>
|
||||
*
|
||||
* <quote>
|
||||
* The minimum indentation (min) is determined as follows:
|
||||
@@ -309,33 +308,36 @@ public final class StringUtil {
|
||||
return maxCommonWs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of
|
||||
*/
|
||||
public static List<Chars> linesWithTrimIndent(String source) {
|
||||
List<String> lines = Arrays.asList(source.split("\n"));
|
||||
List<Chars> result = lines.stream().map(Chars::wrap).collect(CollectionUtil.toMutableList());
|
||||
trimIndentInPlace(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims off the leading characters off the strings up to the trimDepth
|
||||
* specified. Returns the same strings if trimDepth = 0
|
||||
*
|
||||
* @return String[]
|
||||
* @param lines mutable list
|
||||
*/
|
||||
private static String[] trimStartOn(String[] strings, int trimDepth) {
|
||||
|
||||
if (trimDepth == 0) {
|
||||
return strings;
|
||||
public static void trimIndentInPlace(List<Chars> lines) {
|
||||
int trimDepth = maxCommonLeadingWhitespaceForAll(lines);
|
||||
if (trimDepth > 0) {
|
||||
lines.replaceAll(chars -> chars.length() >= trimDepth
|
||||
? chars.subSequence(trimDepth).trimEnd()
|
||||
: chars.trimEnd());
|
||||
}
|
||||
|
||||
String[] results = new String[strings.length];
|
||||
for (int i = 0; i < strings.length; i++) {
|
||||
results[i] = strings[i].substring(trimDepth);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trim common indentation in the lines of the string, like
|
||||
* {@link #appendWithoutCommonPrefix(List, int, StringBuilder)}.
|
||||
*
|
||||
*/
|
||||
public static StringBuilder trimIndent(Chars string) {
|
||||
List<Chars> lines = string.lineStream().collect(Collectors.toList());
|
||||
List<Chars> lines = string.lineStream().collect(CollectionUtil.toMutableList());
|
||||
trimIndentInPlace(lines);
|
||||
|
||||
StringBuilder sb = new StringBuilder(string.length());
|
||||
trimIndentIntoStringBuilder(lines, sb);
|
||||
return sb;
|
||||
@@ -365,7 +367,7 @@ public final class StringUtil {
|
||||
Chars line = lines.get(i);
|
||||
// remove common whitespace prefix
|
||||
if (line.length() >= prefixLength && !StringUtils.isBlank(line)) {
|
||||
line = line.subSequence(prefixLength, line.length());
|
||||
line = line.subSequence(prefixLength);
|
||||
}
|
||||
// trim trailing whitespace
|
||||
line = line.trimEnd();
|
||||
@@ -398,17 +400,21 @@ public final class StringUtil {
|
||||
}
|
||||
}
|
||||
|
||||
int lastNonBlankLine = string.indexOf('\n', offsetOfLastNonBlankChar);
|
||||
int firstNonBlankLine = string.lastIndexOf('\n', offsetOfFirstNonBlankChar);
|
||||
// look backwards before the first non-blank char
|
||||
int cutFromInclusive = string.lastIndexOf('\n', offsetOfFirstNonBlankChar);
|
||||
// If firstNonBlankLineStart == -1, ie we're on the first line,
|
||||
// we want to start at zero: then we add 1 to get 0
|
||||
// If firstNonBlankLineStart >= 0, then it's the index of the
|
||||
// \n, we want to cut right after that, so we add 1.
|
||||
cutFromInclusive += 1;
|
||||
|
||||
return string.subSequence(
|
||||
minus1Default(firstNonBlankLine, 0),
|
||||
minus1Default(lastNonBlankLine, string.length())
|
||||
);
|
||||
}
|
||||
// look forwards after the last non-blank char
|
||||
int cutUntilExclusive = string.indexOf('\n', offsetOfLastNonBlankChar);
|
||||
if (cutUntilExclusive == StringUtils.INDEX_NOT_FOUND) {
|
||||
cutUntilExclusive = string.length();
|
||||
}
|
||||
|
||||
private static int minus1Default(int i, int defaultValue) {
|
||||
return i == -1 ? defaultValue : i;
|
||||
return string.subSequence(cutFromInclusive, cutUntilExclusive);
|
||||
}
|
||||
|
||||
|
||||
@@ -420,15 +426,6 @@ public final class StringUtil {
|
||||
return count;
|
||||
}
|
||||
|
||||
public static String[] linesWithTrimIndent(String source) {
|
||||
String[] lines = source.split("\n");
|
||||
int trimDepth = maxCommonLeadingWhitespaceForAll(Arrays.asList(lines));
|
||||
if (trimDepth > 0) {
|
||||
lines = trimStartOn(lines, trimDepth);
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Are the two String values the same. The Strings can be optionally trimmed
|
||||
|
||||
@@ -94,6 +94,7 @@ public class StringUtilTest {
|
||||
|
||||
assertTrimIndent(" \n b \n c\n ",
|
||||
"\nb\nc\n");
|
||||
assertTrimIndent("", "");
|
||||
}
|
||||
|
||||
private void assertTrimIndent(String input, String output) {
|
||||
@@ -107,4 +108,28 @@ public class StringUtilTest {
|
||||
assertThat(StringUtil.elide("abc", 2, ".."), equalTo(".."));
|
||||
assertThat(StringUtil.elide("abc", 3, ".."), equalTo("abc"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void substringAfterLast() {
|
||||
assertEquals("abc", StringUtil.substringAfterLast("a.abc", '.'));
|
||||
assertEquals("abc", StringUtil.substringAfterLast("abc", '.'));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void trimBlankLines() {
|
||||
assertTrimBlankLinesEquals(" \n \n abc \n \n de \n \n ",
|
||||
" abc \n \n de ");
|
||||
assertTrimBlankLinesEquals("", "");
|
||||
}
|
||||
|
||||
private void assertTrimBlankLinesEquals(String input, String output) {
|
||||
assertEquals(
|
||||
Chars.wrap(output),
|
||||
StringUtil.trimBlankLines(Chars.wrap(input))
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void linesWithTrimIndent() {
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import net.sourceforge.pmd.lang.document.Chars;
|
||||
import net.sourceforge.pmd.util.CollectionUtil;
|
||||
import net.sourceforge.pmd.util.StringUtil;
|
||||
|
||||
/**
|
||||
@@ -83,8 +84,10 @@ public final class ASTStringLiteral extends AbstractLiteral implements ASTLitera
|
||||
|
||||
static String determineTextBlockContent(Chars image) {
|
||||
List<Chars> lines = getContentLines(image);
|
||||
StringBuilder sb = new StringBuilder(image.length());
|
||||
StringUtil.trimIndentIntoStringBuilder(lines, sb);
|
||||
// remove common prefix
|
||||
StringUtil.trimIndentInPlace(lines);
|
||||
// join with normalized end of line
|
||||
StringBuilder sb = CollectionUtil.joinCharsIntoStringBuilder(lines, "\n");
|
||||
interpretEscapeSequences(sb);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user