Skip to content

Commit

Permalink
[enhance] Expose maxPaddingWidth in OutputSettings with default of 30…
Browse files Browse the repository at this point in the history
… retained
  • Loading branch information
hazendaz committed Oct 20, 2021
1 parent 7eb5a74 commit 1a21165
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 12 deletions.
4 changes: 4 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ jsoup changelog
case.
<https://github.com/jhy/jsoup/issues/1656>

* Improvement: allow maxPaddingWidth in OutputSettings for pretty printing. This will continue to default to 30
so very deeply nested nodes don't get insane padding amounts but now allows for user decision. Using -1 will
result in original unlimited length.

*** Release 1.14.3 [2021-Sep-30]
* Improvement: added native XPath support in Element#selectXpath(String)
<https://github.com/jhy/jsoup/pull/1629>
Expand Down
21 changes: 16 additions & 5 deletions src/main/java/org/jsoup/internal/StringUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,10 @@
notice.
*/
public final class StringUtil {
// memoised padding up to 21
// memoised padding up to 21 (blocks 0 to 20 spaces)
static final String[] padding = {"", " ", " ", " ", " ", " ", " ", " ", " ",
" ", " ", " ", " ", " ", " ", " ",
" ", " ", " ", " ", " "};
private static final int maxPaddingWidth = 30; // so very deeply nested nodes don't get insane padding amounts

/**
* Join a collection of strings by a separator
Expand Down Expand Up @@ -115,17 +114,29 @@ public String complete() {
}

/**
* Returns space padding (up to a max of 30).
* Returns space padding (up to a max of 30). Use {@link #padding(int, int)} if you need
* more than 30 spaces padded.
* @param width amount of padding desired
* @return string of spaces * width
*/
*/
public static String padding(int width) {
return padding(width, 30);
}

/**
* Returns space padding (up to a max of maxPaddingWidth - default 30).
* @param width amount of padding desired
* @param maxPaddingWidth amount of max space padding with default set at 30 and -1 means no max.
* @return string of spaces * width
*/
public static String padding(int width, int maxPaddingWidth) {
if (width < 0)
throw new IllegalArgumentException("width must be > 0");

if (width < padding.length)
return padding[width];
width = Math.min(width, maxPaddingWidth);
if (maxPaddingWidth != -1)
width = Math.min(width, maxPaddingWidth);
char[] out = new char[width];
for (int i = 0; i < width; i++)
out[i] = ' ';
Expand Down
24 changes: 23 additions & 1 deletion src/main/java/org/jsoup/nodes/Document.java
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,7 @@ public enum Syntax {html, xml}
private boolean prettyPrint = true;
private boolean outline = false;
private int indentAmount = 1;
private int maxPaddingWidth = 30;
private Syntax syntax = Syntax.html;

public OutputSettings() {}
Expand Down Expand Up @@ -560,6 +561,27 @@ public OutputSettings indentAmount(int indentAmount) {
return this;
}

/**
* Get the current max padding amount, used when pretty printing
* so very deeply nested nodes don't get insane padding amounts.
* @return the current indent amount
*/
public int maxPaddingWidth() {
return maxPaddingWidth;
}

/**
* Set the max padding amount for pretty printing so very deeply nested nodes don't get insane padding amounts.
* @param maxPaddingWidth number of spaces to use for indenting each level of nested nodes. Must be {@literal >=} -1.
* Default is 30 and -1 means unlimited.
* @return this, for chaining
*/
public OutputSettings maxPaddingWidth(int maxPaddingWidth) {
Validate.isTrue(maxPaddingWidth >= -1);
this.maxPaddingWidth = maxPaddingWidth;
return this;
}

@Override
public OutputSettings clone() {
OutputSettings clone;
Expand All @@ -570,7 +592,7 @@ public OutputSettings clone() {
}
clone.charset(charset.name()); // new charset and charset encoder
clone.escapeMode = Entities.EscapeMode.valueOf(escapeMode.name());
// indentAmount, prettyPrint are primitives so object.clone() will handle
// indentAmount, maxPaddingWidth, and prettyPrint are primitives so object.clone() will handle
return clone;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/org/jsoup/nodes/Node.java
Original file line number Diff line number Diff line change
Expand Up @@ -683,7 +683,7 @@ public String toString() {
}

protected void indent(Appendable accum, int depth, Document.OutputSettings out) throws IOException {
accum.append('\n').append(StringUtil.padding(depth * out.indentAmount()));
accum.append('\n').append(StringUtil.padding(depth * out.indentAmount(), out.maxPaddingWidth()));
}

/**
Expand Down
34 changes: 29 additions & 5 deletions src/test/java/org/jsoup/internal/StringUtilTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,35 @@ public void join() {
}

@Test public void padding() {
assertEquals("", StringUtil.padding(0));
assertEquals(" ", StringUtil.padding(1));
assertEquals(" ", StringUtil.padding(2));
assertEquals(" ", StringUtil.padding(15));
assertEquals(" ", StringUtil.padding(45)); // we tap out at 30
// memoization is up to 21 blocks (0 to 20 spaces) and exits early before min checks making maxPaddingWidth unused
assertEquals("", StringUtil.padding(0, -1));
assertEquals(" ", StringUtil.padding(20, -1));

// this test escapes memoization and continues through
assertEquals(" ", StringUtil.padding(21, -1));

// this test escapes memoization and using unlimited length (-1) will allow requested spaces
assertEquals(" ", StringUtil.padding(30, -1));
assertEquals(" ", StringUtil.padding(45, -1));

// we tap out at 0 for this test
assertEquals("", StringUtil.padding(0, 0));

// we tap out at 5 for this test because we do not escape memoization
assertEquals(" ", StringUtil.padding(5, 0));

// as memoization is escaped, setting zero for max padding will not allow any requested width
assertEquals("", StringUtil.padding(21, 0));

// we tap out at 30 for these tests making > 30 use 30
assertEquals("", StringUtil.padding(0, 30));
assertEquals(" ", StringUtil.padding(1, 30));
assertEquals(" ", StringUtil.padding(2, 30));
assertEquals(" ", StringUtil.padding(15, 30));
assertEquals(" ", StringUtil.padding(45, 30));

// Testing deprecated version capped at 30
assertEquals(" ", StringUtil.padding(45));
}

@Test public void paddingInACan() {
Expand Down

0 comments on commit 1a21165

Please sign in to comment.