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
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Changelog

* `0.9.0`:
* `1.0.0`:
- Supports pausing and resuming progress bars (PR #63), thereby fixing #17. Thanks @mesat !

* `0.8.1`:
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
11 changes: 6 additions & 5 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@
<url>http://github.com/ctongfei/progressbar</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>1.8</maven.compiler.target>
<maven.compiler.source>1.8</maven.compiler.source>
<jline.version>3.14.0</jline.version>
</properties>

<licenses>
Expand Down Expand Up @@ -88,13 +89,13 @@
<dependency>
<groupId>org.jline</groupId>
<artifactId>jline</artifactId>
<version>3.13.3</version>
<version>${jline.version}</version>
</dependency>

<dependency>
<groupId>org.jline</groupId>
<artifactId>jline-terminal-jansi</artifactId>
<version>3.13.3</version>
<version>${jline.version}</version>
</dependency>

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

import org.jline.terminal.Terminal;

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

import static me.tongfei.progressbar.TerminalUtils.MOVE_CURSOR_TO_LINE_START;

/**
* 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 int consoleRightMargin = 2;
private final PrintStream out;
private Terminal terminal = Util.getTerminal();

ConsoleProgressBarConsumer() {
this(System.err);
}
final PrintStream out;

ConsoleProgressBarConsumer(PrintStream out) {
public ConsoleProgressBarConsumer(PrintStream out) {
this.out = out;
}

@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);
out.print(MOVE_CURSOR_TO_LINE_START + str);
}

@Override
public void close() {
out.println();
out.flush();
try {
terminal.close();
}
catch (IOException ignored) { /* noop */ }
}
}
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package me.tongfei.progressbar;

import java.io.PrintStream;

import static me.tongfei.progressbar.TerminalUtils.*;

/**
* Progress bar consumer for terminals supporting moving cursor up/down.
*
* @author Martin Vehovsky
*/
public class InteractiveConsoleProgressBarConsumer extends ConsoleProgressBarConsumer {

private boolean initialized = false;
int position = 1;

public InteractiveConsoleProgressBarConsumer(PrintStream out) {
super(out);
}

@Override
public void accept(String str) {
if (!initialized) {
TerminalUtils.filterActiveConsumers(InteractiveConsoleProgressBarConsumer.class).forEach(c -> c.position++);
TerminalUtils.activeConsumers.add(this);
out.println(MOVE_CURSOR_TO_LINE_START + str);
initialized = true;
return;
}

out.print(moveCursorUp(position) + str + moveCursorDown(position));
}

@Override
public void close() {
out.flush();
TerminalUtils.activeConsumers.remove(this);
}
}
39 changes: 27 additions & 12 deletions src/main/java/me/tongfei/progressbar/ProgressBar.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,15 @@
import java.util.Iterator;
import java.util.List;
import java.util.Spliterator;
import java.util.concurrent.ExecutionException;
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;

import static me.tongfei.progressbar.Util.createConsoleConsumer;

/**
* A console-based progress bar with minimal runtime overhead.
* @author Tongfei Chen
Expand All @@ -27,7 +32,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 @@ -92,9 +97,9 @@ public ProgressBar(
long startFrom,
Duration elapsed
) {
this(task, initialMax, updateIntervalMillis, startFrom, elapsed,
new DefaultProgressBarRenderer(style, unitName, unitSize, showSpeed, speedFormat, speedUnit),
new ConsoleProgressBarConsumer(os)
this(task, initialMax, updateIntervalMillis,
new DefaultProgressBarRenderer(style, unitName, unitSize, showSpeed, speedFormat),
createConsoleConsumer(os)
);
}

Expand All @@ -120,11 +125,20 @@ public ProgressBar(
) {
this.progress = new ProgressState(task, initialMax, startFrom, elapsed);
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().minus(elapsed.getSeconds(), ChronoUnit.SECONDS);
thread.start();
progress.startTime = Instant.now();
scheduled = Util.executor.scheduleAtFixedRate(target, 0, updateIntervalMillis, TimeUnit.MILLISECONDS);
}

/**
* Starts this progress bar.
* @deprecated Please use the Java try-with-resource pattern instead.
*/
@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();
scheduled = Util.executor.scheduleAtFixedRate(target, 0, target.updateInterval, TimeUnit.MILLISECONDS);
return this;
}

/**
Expand Down Expand Up @@ -206,12 +220,13 @@ public ProgressBar stop() {
*/
@Override
public void close() {
thread.interrupt();
scheduled.cancel(false);
target.setActive(false);
try {
thread.join();
target.closeConsumer();
Util.executor.schedule(target, 0, TimeUnit.NANOSECONDS).get();
} catch (InterruptedException | ExecutionException e) {
//noop
}
catch (InterruptedException ignored) { }
}

/**
Expand Down
6 changes: 4 additions & 2 deletions src/main/java/me/tongfei/progressbar/ProgressBarBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import java.time.Duration;
import java.time.temporal.ChronoUnit;

import static me.tongfei.progressbar.Util.createConsoleConsumer;

/**
* Builder class for {@link ProgressBar}s.
* @author Tongfei Chen
Expand All @@ -12,7 +14,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 Expand Up @@ -85,7 +87,7 @@ public ProgressBarBuilder startsFrom(long processed, Duration elapsed) {

public ProgressBar build() {
if (consumer == null)
consumer = new ConsoleProgressBarConsumer();
consumer = createConsoleConsumer();

return new ProgressBar(
task,
Expand Down
22 changes: 9 additions & 13 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 @@ -20,6 +10,7 @@ class ProgressThread implements Runnable {
private long updateInterval;
private ProgressBarRenderer renderer;
private ProgressBarConsumer consumer;
private boolean active = true;

private boolean paused;

Expand Down Expand Up @@ -48,10 +39,11 @@ private void refresh() {
consumer.accept(rendered);
}

void closeConsumer() {
consumer.close();
public void setActive(boolean active) {
this.active = active;
}

@Override
public void run() {
try {
while (!Thread.interrupted()) {
Expand All @@ -61,8 +53,12 @@ public void run() {
}
} catch (InterruptedException ignored) {
refresh();
// force refreshing after being interrupted
consumer.close();
TerminalUtils.closeTerminal();
return;
}

refresh();
}

}
Loading