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

Added support for multiple progress bars displayed simultaneously #69

Merged
merged 11 commits into from
Apr 24, 2020
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

* `0.8.1`:
- Bugfixes:
- Fixed the bug of possible negative suffix length (PR #58). Thanks @kristofarkas !
- Fixed the issue of stepping by -1 when wrapped input stream is depleted (#60, PR #61). Thanks @mordechaim !
- Default value for initial max in progress bar builders should be -1, not 0 (#60, PR #61). Thanks @mordechaim !
- Dependency version bump.

* `0.8.0`:
- Supports loggers (PR #54) by factoring out progress bar consumers and renderers. This allows progress bars to be used with logging libraries such as SLF4J, hence fixing #12 and #18. Thanks @alexpeelman !
- Dependency version bump.
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2015--2019 Tongfei Chen
Copyright (c) 2015--2020 Tongfei Chen

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ A console progress bar for JVM with minimal runtime overhead.

Menlo,
[Fira Mono](https://github.com/mozilla/Fira),
[Source Code Pro](https://github.com/adobe-fonts/source-code-pro) or
[Source Code Pro](https://github.com/adobe-fonts/source-code-pro),
[Iosevka](https://github.com/be5invis/Iosevka), or
[SF Mono](https://developer.apple.com/fonts/) are recommended for optimal visual effects.

For Consolas or Andale Mono fonts, use `ProgressBarStyle.ASCII` because the box-drawing glyphs are not aligned properly in these fonts.
Expand All @@ -27,7 +28,7 @@ Maven:
<dependency>
<groupId>me.tongfei</groupId>
<artifactId>progressbar</artifactId>
<version>0.8.0</version>
<version>0.8.1</version>
</dependency>
```

Expand Down
4 changes: 2 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ Depending on your build tool, add the following setting.
<dependency>
<groupId>me.tongfei</groupId>
<artifactId>progressbar</artifactId>
<version>0.8.0</version>
<version>0.8.1</version>
</dependency>
```

``` groovy fct_label="Gradle"
compile 'me.tongfei:progressbar:0.8.0'
compile 'me.tongfei:progressbar:0.8.1'
```

#### Getting started
Expand Down
6 changes: 3 additions & 3 deletions mkdocs.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
site_name: 'Progressbar 0.8.0'
site_description: 'A console progress bar for Java/JVM'
site_name: 'Progressbar 0.8.1'
site_description: 'A terminal progress bar for Java/JVM'
site_author: 'Tongfei Chen'
copyright: 'Copyright &copy; 2015-2019 Tongfei Chen'
copyright: 'Copyright &copy; 2015-2020 Tongfei Chen'

theme:
name: 'material'
Expand Down
18 changes: 13 additions & 5 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@

<groupId>me.tongfei</groupId>
<artifactId>progressbar</artifactId>
<version>0.8.0</version>
<version>0.8.1</version>
<name>progressbar</name>
<description>A console-based progress bar for JVM</description>
<description>A terminal-based progress bar for JVM</description>
<url>http://github.com/ctongfei/progressbar</url>

<properties>
Expand Down Expand Up @@ -70,25 +70,33 @@
<id>alexpeelman</id>
<name>Alex Peelman</name>
</developer>
<developer>
<id>kristofarkas</id>
<name>Kristof Farkas-Pall</name>
</developer>
<developer>
<id>mordechaim</id>
<name>Mordechai Meisels</name>
</developer>
</developers>

<dependencies>
<dependency>
<groupId>org.jline</groupId>
<artifactId>jline</artifactId>
<version>3.13.2</version>
<version>3.14.0</version>
</dependency>

<dependency>
<groupId>org.jline</groupId>
<artifactId>jline-terminal-jansi</artifactId>
<version>3.13.2</version>
<version>3.14.0</version>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<version>4.13</version>
<scope>test</scope>
</dependency>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,48 +1,77 @@
package me.tongfei.progressbar;

import org.jline.terminal.Terminal;

import java.io.IOException;
import java.io.PrintStream;

/**
* Progress bar consumer that prints the progress bar state to console.
* By default {@link System#err} is used as {@link PrintStream}.
*
* @author Tongfei Chen
* @author Alex Peelman
*/
public class ConsoleProgressBarConsumer implements ProgressBarConsumer {

private static final char MOVE_CURSOR_TO_LINE_START = '\r';
private static int consoleRightMargin = 2;
private final PrintStream out;
private Terminal terminal = Util.getTerminal();
private final boolean cursorMovementSupport;
final PrintStream out;

private boolean initialized = false;
int position = -1;

ConsoleProgressBarConsumer() {
this(System.err);
}

ConsoleProgressBarConsumer(PrintStream out) {
this.out = out;
cursorMovementSupport = TerminalUtils.cursorMovementSupport();
}

@Override
public int getMaxProgressLength() {
return Util.getTerminalWidth(terminal) - consoleRightMargin;
return TerminalUtils.getTerminalWidth() - consoleRightMargin;
}

@Override
public void accept(String str) {
out.print('\r'); // before update
out.print(str);
if (cursorMovementSupport) {
synchronized (out) {
if (initialized) {
out.print(moveCursorUp(position) + str + moveCursorDown(position));
} else {
TerminalUtils.filterActiveConsumers(ConsoleProgressBarConsumer.class).forEach(c -> c.position++);
TerminalUtils.activeConsumers.add(this);
out.println(MOVE_CURSOR_TO_LINE_START + str);
position = 1;
initialized = true;
}
}
} else {
out.print(MOVE_CURSOR_TO_LINE_START + str);
}
}

private String moveCursorUp(int count) {
if (count <= 0) {
return "";
}
return String.format("\u001b[%sA", count) + MOVE_CURSOR_TO_LINE_START;
}

private String moveCursorDown(int count) {
if (count <= 0) {
return "";
}
return String.format("\u001b[%sB", count) + MOVE_CURSOR_TO_LINE_START;
}

@Override
public void close() {
out.println();
out.flush();
try {
terminal.close();
if (!cursorMovementSupport) {
out.println();
}
catch (IOException ignored) { /* noop */ }
out.flush();
TerminalUtils.activeConsumers.remove(this);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class DelegatingProgressBarConsumer implements ProgressBarConsumer {
private final Consumer<String> consumer;

public DelegatingProgressBarConsumer(Consumer<String> consumer) {
this(consumer, Util.getTerminalWidth());
this(consumer, TerminalUtils.getTerminalWidth());
}

public DelegatingProgressBarConsumer(Consumer<String> consumer, int maxProgressLength) {
Expand Down
18 changes: 7 additions & 11 deletions src/main/java/me/tongfei/progressbar/ProgressBar.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import java.time.Instant;
import java.util.Iterator;
import java.util.Spliterator;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.BaseStream;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
Expand All @@ -23,7 +25,7 @@ public class ProgressBar implements AutoCloseable {

private ProgressState progress;
private ProgressThread target;
private Thread thread;
private ScheduledFuture scheduled;

/**
* Creates a progress bar with the specific task name and initial maximum value.
Expand Down Expand Up @@ -109,11 +111,9 @@ public ProgressBar(
) {
this.progress = new ProgressState(task, initialMax);
this.target = new ProgressThread(progress, renderer, updateIntervalMillis, consumer);
this.thread = new Thread(target, this.getClass().getName());

// starts the progress bar upon construction
progress.startTime = Instant.now();
thread.start();
scheduled = Util.executor.scheduleAtFixedRate(target, 0, updateIntervalMillis, TimeUnit.MILLISECONDS);
}

/**
Expand All @@ -123,7 +123,7 @@ public ProgressBar(
@Deprecated
public ProgressBar start() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly I don't see point in keeping this deprecated method in the public API. There is no way anymore (even before this PR) to construct the ProgressBar without the Runnable being started. Personally I would remove it and made the updateInterval private again in ProgressThread.

progress.startTime = Instant.now();
thread.start();
scheduled = Util.executor.scheduleAtFixedRate(target, 0, target.updateInterval, TimeUnit.MILLISECONDS);
return this;
}

Expand Down Expand Up @@ -188,12 +188,8 @@ public ProgressBar stop() {
*/
@Override
public void close() {
thread.interrupt();
try {
thread.join();
target.closeConsumer();
}
catch (InterruptedException ignored) { }
scheduled.cancel(false);
target.closeConsumer();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
public class ProgressBarBuilder {

private String task = "";
private long initialMax = 0;
private long initialMax = -1;
private int updateIntervalMillis = 1000;
private ProgressBarStyle style = ProgressBarStyle.COLORFUL_UNICODE_BLOCK;
private ProgressBarConsumer consumer = null;
Expand Down
32 changes: 12 additions & 20 deletions src/main/java/me/tongfei/progressbar/ProgressThread.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,5 @@
package me.tongfei.progressbar;

import java.io.PrintStream;
import java.io.IOException;
import java.text.DecimalFormat;
import java.time.Duration;
import java.time.Instant;
import java.util.function.Consumer;

import org.jline.terminal.Terminal;
import org.jline.terminal.TerminalBuilder;

/**
* @author Tongfei Chen
* @since 0.5.0
Expand All @@ -18,7 +8,7 @@ class ProgressThread implements Runnable {

private ProgressState progress;
private ProgressBarRenderer renderer;
private long updateInterval;
long updateInterval;
private ProgressBarConsumer consumer;

ProgressThread(
Expand All @@ -39,19 +29,21 @@ private void refresh() {
}

void closeConsumer() {
if (consumer instanceof ConsoleProgressBarConsumer) {
synchronized (((ConsoleProgressBarConsumer) consumer).out) {
// force refreshing after being "interrupted"
refresh();
consumer.close();
}
return;
}
// force refreshing after being "interrupted"
refresh();
consumer.close();
}

public void run() {
try {
while (!Thread.interrupted()) {
refresh();
Thread.sleep(updateInterval);
}
} catch (InterruptedException ignored) {
refresh();
// force refreshing after being interrupted
}
refresh();
}

}
Loading