Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.10.0 #155

Merged
merged 6 commits into from
Aug 11, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Support ANSI colors and write documentation
Now a user can define theirs own symbols for
the progress bar. Also, ANSI colors are supported.

The change is backward-compatible.
  • Loading branch information
PakhomovAlexander committed Mar 16, 2023
commit 03b4efc50e217074e8aab5c852c80cdef5a22722
17 changes: 17 additions & 0 deletions docs/builder.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,20 @@ for (T x : ProgressBar.wrap(collection, pbb)) {
...
}
```

Since `0.9.6` you can customize the progress bar style:

``` java
ProgressBarBuilder pbb = new ProgressBarBuilder()
// ...
.setStyle(DrawStyle.builder()
// the color index from 0 to 255 (Ansi color table)
.colorCode(33)
.leftBracket("{")
.rightBracket("}")
.block('-')
.rightSideFractionSymbol('+')
.build()
)
// ...
```
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
*/
public class DefaultProgressBarRenderer implements ProgressBarRenderer {

private ProgressBarStyle style;
private DrawStyle style;
private String unitName;
private long unitSize;
private boolean isSpeedShown;
Expand All @@ -27,7 +27,7 @@ public class DefaultProgressBarRenderer implements ProgressBarRenderer {
private Function<ProgressState, Optional<Duration>> eta;

protected DefaultProgressBarRenderer(
ProgressBarStyle style,
DrawStyle style,
String unitName,
long unitSize,
boolean isSpeedShown,
Expand All @@ -53,7 +53,7 @@ protected int progressIntegralPart(ProgressState progress, int length) {

protected int progressFractionalPart(ProgressState progress, int length) {
double p = progress.getNormalizedProgress() * length;
double fraction = (p - Math.floor(p)) * style.fractionSymbols.length();
double fraction = (p - Math.floor(p)) * style.fractionSymbols().length();
return (int) Math.floor(fraction);
}

Expand Down Expand Up @@ -112,7 +112,7 @@ public String render(ProgressState progress, int maxLength) {
return "";
}

String prefix = progress.getTaskName() + " " + percentage(progress) + " " + style.leftBracket;
String prefix = progress.getTaskName() + " " + percentage(progress) + " " + style.leftBracket();
int prefixLength = getStringDisplayLength(prefix);

if (prefixLength > maxLength) {
Expand All @@ -124,7 +124,7 @@ public String render(ProgressState progress, int maxLength) {
int maxSuffixLength = Math.max(maxLength - prefixLength - 1, 0);

String speedString = isSpeedShown ? speed(progress) : "";
String suffix = style.rightBracket + " " + ratio(progress) + " ("
String suffix = style.rightBracket() + " " + ratio(progress) + " ("
+ Util.formatDuration(progress.getTotalElapsed())
+ (isEtaShown ? " / " + etaString(progress) : "")
+ ") "
Expand All @@ -144,24 +144,24 @@ public String render(ProgressState progress, int maxLength) {
// case of indefinite progress bars
if (progress.indefinite) {
int pos = (int)(progress.current % length);
sb.append(Util.repeat(style.space, pos));
sb.append(style.block);
sb.append(Util.repeat(style.space, length - pos - 1));
sb.append(Util.repeat(style.space(), pos));
sb.append(style.block());
sb.append(Util.repeat(style.space(), length - pos - 1));
}
// case of definite progress bars
else {
sb.append(Util.repeat(style.block, progressIntegralPart(progress, length)));
sb.append(Util.repeat(style.block(), progressIntegralPart(progress, length)));
if (progress.current < progress.max) {
int fraction = progressFractionalPart(progress, length);
if (fraction != 0) {
sb.append(style.fractionSymbols.charAt(fraction));
sb.append(style.delimitingSequence);
sb.append(style.fractionSymbols().charAt(fraction));
sb.append(style.delimitingSequence());
}
else {
sb.append(style.delimitingSequence);
sb.append(style.rightSideFractionSymbol);
sb.append(style.delimitingSequence());
sb.append(style.rightSideFractionSymbol());
}
sb.append(Util.repeat(style.space, length - progressIntegralPart(progress, length) - 1));
sb.append(Util.repeat(style.space(), length - progressIntegralPart(progress, length) - 1));
}
}

Expand Down
42 changes: 42 additions & 0 deletions src/main/java/me/tongfei/progressbar/DrawStyle.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package me.tongfei.progressbar;

/**
* A draw style for a progress bar.
*
* @author Aleksandr Pakhomov
*/
public interface DrawStyle {
/** Create draw style object from {@link ProgressBarStyle} */
static DrawStyle from(ProgressBarStyle style) {
return builder().apply(style).build();
}

/** Symbol to refresh the progress bar. */
String refreshPrompt();

/** Left bracket of the progress bar. */
String leftBracket();

/** Delimiting sequence between the progress bar and the status text. */
String delimitingSequence();

/** Right bracket of the progress bar. */
String rightBracket();

/** Block character of the progress bar. [=====> ] here '=' is the block. */
char block();

/** Space character of the progress bar. [=====> ] here ' ' is the space. */
char space();

/** Fraction symbols of the progress bar. */
String fractionSymbols();

/** Right side fraction symbol of the progress bar. [=====> ] here '>'. */
char rightSideFractionSymbol();

/** Create a new builder for {@link DrawStyle} */
static DrawStyleBuilder builder() {
return new DrawStyleBuilder();
}
}
168 changes: 168 additions & 0 deletions src/main/java/me/tongfei/progressbar/DrawStyleBuilder.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
package me.tongfei.progressbar;

/**
* Builder for {@link DrawStyle}.
*
* @author Aleksandr Pakhomov
*/
public class DrawStyleBuilder {
private static final String ESC_CODE = "\u001b[";

private String refreshPrompt = "\r";
private String leftBracket = "[";
private String delimitingSequence = "";
private String rightBracket = "]";
private char block = '=';
private char space = ' ';
private String fractionSymbols = ">";
private char rightSideFractionSymbol = '>';
private int colorCode = 0;

/** Set refresh prompt. Default "\r". */
public DrawStyleBuilder refreshPrompt(String refreshPrompt) {
this.refreshPrompt = refreshPrompt;
return this;
}

/** Set left bracket. Default "[". */
public DrawStyleBuilder leftBracket(String leftBracket) {
this.leftBracket = leftBracket;
return this;
}

/** Set delimiting sequence. Default "". */
public DrawStyleBuilder delimitingSequence(String delimitingSequence) {
this.delimitingSequence = delimitingSequence;
return this;
}

/** Set right bracket. Default "]". */
public DrawStyleBuilder rightBracket(String rightBracket) {
this.rightBracket = rightBracket;
return this;
}

/** Set block character. Default "=" */
public DrawStyleBuilder block(char block) {
this.block = block;
return this;
}

/** Set space character. Default " " */
public DrawStyleBuilder space(char space) {
this.space = space;
return this;
}

/** Set fraction symbols. Default ">" */
public DrawStyleBuilder fractionSymbols(String fractionSymbols) {
this.fractionSymbols = fractionSymbols;
return this;
}

/** Set right side fraction symbol. Default ">" */
public DrawStyleBuilder rightSideFractionSymbol(char rightSideFractionSymbol) {
this.rightSideFractionSymbol = rightSideFractionSymbol;
return this;
}

/** Set ANSI color code. Default 0 (no color). Must be in [0, 255]. */
public DrawStyleBuilder colorCode(int code) {
if (code < 0 || code > 255)
throw new IllegalArgumentException("Color code must be between 0 and 255.");

this.colorCode = code;
return this;
}

/** Build {@link DrawStyle}. */
public DrawStyle build() {
boolean colorDefined = colorCode != 0;

if (colorDefined && leftBracket.contains(ESC_CODE)) {
throw new IllegalArgumentException("The color code is overridden with left bracket escape code. "
+ "Please, remove the escape sequence from the left bracket or do not use color code.");
}

String prefix = colorDefined ? (ESC_CODE + colorCode + "m") : "";
String postfix = colorDefined ? ESC_CODE + "0m" : "";

return new InternalDrawStyle(refreshPrompt, prefix + leftBracket, delimitingSequence,
rightBracket + postfix, block, space, fractionSymbols, rightSideFractionSymbol);
}

/** Apply {@link ProgressBarStyle}. */
public DrawStyleBuilder apply(ProgressBarStyle style) {
refreshPrompt(style.refreshPrompt);
leftBracket(style.leftBracket);
delimitingSequence(style.delimitingSequence);
rightBracket(style.rightBracket);
block(style.block);
space(style.space);
fractionSymbols(style.fractionSymbols);
return rightSideFractionSymbol(style.rightSideFractionSymbol);
}

static class InternalDrawStyle implements DrawStyle {
private final String refreshPrompt;
private final String leftBracket;
private final String delimitingSequence;
private final String rightBracket;
private final char block;
private final char space;
private final String fractionSymbols;
private final char rightSideFractionSymbol;

private InternalDrawStyle(String refreshPrompt, String leftBracket, String delimitingSequence,
String rightBracket, char block, char space, String fractionSymbols, char rightSideFractionSymbol) {
this.refreshPrompt = refreshPrompt;
this.leftBracket = leftBracket;
this.delimitingSequence = delimitingSequence;
this.rightBracket = rightBracket;
this.block = block;
this.space = space;
this.fractionSymbols = fractionSymbols;
this.rightSideFractionSymbol = rightSideFractionSymbol;
}

@Override
public String refreshPrompt() {
return refreshPrompt;
}

@Override
public String leftBracket() {
return leftBracket;
}

@Override
public String delimitingSequence() {
return delimitingSequence;
}

@Override
public String rightBracket() {
return rightBracket;
}

@Override
public char block() {
return block;
}

@Override
public char space() {
return space;
}

@Override
public String fractionSymbols() {
return fractionSymbols;
}

@Override
public char rightSideFractionSymbol() {
return rightSideFractionSymbol;
}
}
}
36 changes: 34 additions & 2 deletions src/main/java/me/tongfei/progressbar/ProgressBar.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public ProgressBar(String task, long initialMax) {
* @param initialMax Initial maximum value
* @param updateIntervalMillis Update interval (default value 1000 ms)
* @param continuousUpdate Rerender every time the update interval happens regardless of progress count.
* @param style Output style (default value ProgressBarStyle.UNICODE_BLOCK)
* @param style Draw style
* @param showSpeed Should the calculated speed be displayed
* @param speedFormat Speed number format
* @deprecated Use {@link ProgressBarBuilder} instead.
Expand All @@ -62,7 +62,7 @@ public ProgressBar(
boolean continuousUpdate,
boolean clearDisplayOnFinish,
PrintStream os,
ProgressBarStyle style,
DrawStyle style,
String unitName,
long unitSize,
boolean showSpeed,
Expand All @@ -81,6 +81,38 @@ public ProgressBar(
);
}

/**
* Creates a progress bar with the specific taskName name, initial maximum value,
* customized update interval (default 1000 ms), the PrintStream to be used, and output style.
* @param task Task name
* @param initialMax Initial maximum value
* @param updateIntervalMillis Update interval (default value 1000 ms)
* @param continuousUpdate Rerender every time the update interval happens regardless of progress count.
* @param style Output style (default value ProgressBarStyle.UNICODE_BLOCK)
* @param showSpeed Should the calculated speed be displayed
* @param speedFormat Speed number format
* @deprecated Use {@link ProgressBarBuilder} instead.
*/
public ProgressBar(
String task,
long initialMax,
int updateIntervalMillis,
boolean continuousUpdate,
boolean clearDisplayOnFinish,
PrintStream os,
ProgressBarStyle style,
String unitName,
long unitSize,
boolean showSpeed,
DecimalFormat speedFormat,
ChronoUnit speedUnit,
long processed,
Duration elapsed
) {
this(task, initialMax, updateIntervalMillis, continuousUpdate, clearDisplayOnFinish, os,
DrawStyle.from(style), unitName, unitSize, showSpeed, speedFormat, speedUnit, processed, elapsed);
}

/**
* Creates a progress bar with the specific name, initial maximum value, customized update interval (default 1s),
* and the provided progress bar renderer ({@link ProgressBarRenderer}) and consumer ({@link ProgressBarConsumer}).
Expand Down
7 changes: 6 additions & 1 deletion src/main/java/me/tongfei/progressbar/ProgressBarBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class ProgressBarBuilder {
private long initialMax = -1;
private int updateIntervalMillis = 1000;
private boolean continuousUpdate = false;
private ProgressBarStyle style = ProgressBarStyle.COLORFUL_UNICODE_BLOCK;
private DrawStyle style = DrawStyle.from(ProgressBarStyle.COLORFUL_UNICODE_BLOCK);
private ProgressBarConsumer consumer = null;
private boolean clearDisplayOnFinish = false;
private String unitName = "";
Expand Down Expand Up @@ -48,6 +48,11 @@ public ProgressBarBuilder setInitialMax(long initialMax) {
}

public ProgressBarBuilder setStyle(ProgressBarStyle style) {
this.style = DrawStyle.from(style);
return this;
}

public ProgressBarBuilder setStyle(DrawStyle style) {
this.style = style;
return this;
}
Expand Down
Loading