6 Commits
1.0 ... 1.2.3

8 changed files with 131 additions and 44 deletions

View File

@ -1,4 +1,4 @@
Copyright (c) 2014 Copyright (c) 2016
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -24,4 +24,4 @@ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

45
README.md Normal file
View File

@ -0,0 +1,45 @@
# Console Progress Bar
Simple progress bar for long-running operations.
## Java/Groovy
Build with gradle:
gradle assemble
Example usage:
```java
import com.jdbernard.util.ConsoleProgressBar
// ...
ConsoleProgressBar progressBar = new ConsoleProgressBar()
progressBar.setOut(System.out) // optional
progressBar.setMax(100)
for (int i = 0; i <= 100; i++) {
progressBar.update(i, "Message for " + i);
Thread.sleep(500);
}
```
## Nim
Install the library using nimble:
nimble install
Example usage:
```nim
import os, console_progress
var progress = newProgress(sout = stdout, maxValue = 100)
for i in 0..100:
progress.updateProgress(i, "Message for " & i)
sleep(500)
```

View File

@ -2,7 +2,7 @@ apply plugin: "groovy"
apply plugin: "maven" apply plugin: "maven"
group = "com.jdbernard" group = "com.jdbernard"
version = "1.0" version = "1.2.2"
repositories { repositories {
mavenLocal() mavenLocal()

View File

@ -1,6 +1,6 @@
# Package # Package
version = "1.0" version = "1.2.3"
author = "Jonathan Bernard" author = "Jonathan Bernard"
description = "Utility for writing dynamic progress bars to the console." description = "Utility for writing dynamic progress bars to the console."
license = "BSD" license = "BSD"
@ -9,4 +9,3 @@ srcDir = "src/main/nim"
# Dependencies # Dependencies
requires "nim >= 0.13.0" requires "nim >= 0.13.0"

View File

@ -8,20 +8,20 @@ package com.jdbernard.util
* counter is 1-based because the current step is complete for this counter. * counter is 1-based because the current step is complete for this counter.
* @author Jonathan Bernard (jdbernard@gmail.com) * @author Jonathan Bernard (jdbernard@gmail.com)
*/ */
class ConsoleProgressBar { public class ConsoleProgressBar {
int MAX_STEP = 30 int WIDTH = 79
int MAX_STEP = 35
long max = 10 long max = 10
def out = System.out def out = System.out
private int lastStepAmount = -1 private int lastStepAmount = -1
private String lastLinePrinted = ""
private String lastInfo = "" private String lastInfo = ""
private long startTime private long startTime
public void setMax(long max) { public void setMax(long max) {
this.max = Math.max(max, 1) } this.max = Math.max(max, 1) }
void update(long value, String info) { public void update(long value, String info) {
if (value == 0 || startTime == 0) if (value == 0 || startTime == 0)
startTime = System.currentTimeMillis() startTime = System.currentTimeMillis()
@ -50,20 +50,17 @@ class ConsoleProgressBar {
if (info.length() > 16) info = info[0..<16] if (info.length() > 16) info = info[0..<16]
if (info.length() < 16) info = info.padRight(16) if (info.length() < 16) info = info.padRight(16)
out.print '\b' * lastLinePrinted.length() out.print '\b' * WIDTH
lastLinePrinted = '=' * numEq + (curStep > 0 ? "0" : "") + '-' * (MAX_STEP - curStep) def line = = '=' * numEq + (curStep > 0 ? "0" : "") + '-' * (MAX_STEP - curStep)
lastLinePrinted += " ${info} -- (" + line += " ${info} -- (" +
"${String.format('%5.2f', curPercent * 100)}%, ${remMin ? remMin + 'm ' : ''}${remSec}s) " "${String.format('%5.2f', curPercent * 100)}%, ${remMin ? remMin + 'm ' : ''}${remSec}s) "
out.print lastLinePrinted out.print line.padRight(WIDTH)
lastStepAmount = curStep; lastStepAmount = curStep;
} }
out.flush() out.flush()
} }
void erase() { public void erase() {
out.print '\b' * lastLinePrinted.length() out.print ('\b' * WIDTH) + (' ' * WIDTH) + ('\b' * WIDTH)
out.print ' ' * lastLinePrinted.length()
out.print '\b' * lastLinePrinted.length()
lastLinePrinted = ""
} }
} }

View File

@ -1,11 +1,37 @@
import strutils, times, math import strutils, times, math
type Progress* = ref object of RootObj type
sout: File PBDisplayConfig* = object
lastStep, maxSteps: int ## Progress Bar Display Configuration - controls how the progress bar is
startTime: float ## displayed to the terminal
lastLinePrinted, lastInfo: string before*: string ## Written at the start, before the bar. This is
maxValue: BiggestInt ## intended for ANSI control characters and must take
## up zero characters when printed.
after*: string ## Written at the end, after the bar This is intended
## for ANSI control characters and must take up zero
## characters when printed.
completed*: string ## Written for each completed step of the bar. This
## should take up one character of space when printed.
todo*: string ## Written for each step remaining in the bar. This
## should take up one character of space when printed.
separator*: string ## Written for the current step, separating completed
## and done. This should take up one character of space
## when printed.
Progress* = ref object of RootObj
sout: File
lastStep, width, maxSteps: int
startTime: float
lastInfo: string
maxValue: BiggestInt
displayCfg: PBDisplayConfig
const DEFAULT_DISPLAY_CFG* = PBDisplayConfig(
before: "\x1b[38;5;2m",
after: "\x1b[0m",
completed: "",
todo: "",
separator: "𜱶\x1b[38;5;8m")
proc getMax*(pd: Progress): BiggestInt = proc getMax*(pd: Progress): BiggestInt =
return pd.maxValue return pd.maxValue
@ -13,13 +39,20 @@ proc getMax*(pd: Progress): BiggestInt =
proc setMax*(pd: Progress, maxValue: BiggestInt) = proc setMax*(pd: Progress, maxValue: BiggestInt) =
pd.maxValue = max(maxValue, 1) pd.maxValue = max(maxValue, 1)
proc newProgress*(sout: File, maxValue: BiggestInt): Progress = proc newProgress*(
maxValue: BiggestInt,
sout: File = stdout,
width: int = 79,
maxSteps: int = 35,
displayCfg: PBDisplayConfig = DEFAULT_DISPLAY_CFG): Progress =
return Progress(sout: sout, return Progress(sout: sout,
startTime: cpuTime(), startTime: cpuTime(),
lastStep: 0, lastStep: 0,
lastLinePrinted: "",
maxValue: maxValue, maxValue: maxValue,
maxSteps: 30) width: 79,
maxSteps: 35,
displayCfg: displayCfg)
proc updateProgress*(pd: Progress, newValue: BiggestInt, info: string): void = proc updateProgress*(pd: Progress, newValue: BiggestInt, info: string): void =
@ -30,9 +63,11 @@ proc updateProgress*(pd: Progress, newValue: BiggestInt, info: string): void =
if info == pd.lastInfo and curStep == pd.lastStep: return if info == pd.lastInfo and curStep == pd.lastStep: return
let curTime = cpuTime() let curDuration = cpuTime() - pd.startTime
let remTime = ((curTime / curPercent) - curTime) * 1000 let remTime = ((curDuration / curPercent) - curDuration)
let displayedSteps = max(curStep - 1, 0) let displayedSteps =
if curStep == pd.maxSteps: curStep
else: max(curStep - 1, 0)
pd.lastInfo = info pd.lastInfo = info
var displayedInfo = info var displayedInfo = info
@ -40,29 +75,32 @@ proc updateProgress*(pd: Progress, newValue: BiggestInt, info: string): void =
if displayedInfo.len < 16: if displayedInfo.len < 16:
displayedInfo = displayedInfo & ' '.repeat(16 - displayedInfo.len) displayedInfo = displayedInfo & ' '.repeat(16 - displayedInfo.len)
pd.sout.write('\b'.repeat(pd.lastLinePrinted.len)) pd.sout.write('\b'.repeat(pd.width))
pd.lastLinePrinted = var line =
'='.repeat(displayedSteps) & (if curStep > 0: "0" else: "") & pd.displayCfg.before &
'-'.repeat(pd.maxSteps - curStep) & " " & pd.displayCfg.completed.repeat(displayedSteps) &
(if curStep > 0 and curStep < pd.maxSteps: pd.displayCfg.separator else: "") &
pd.displayCfg.todo.repeat(pd.maxSteps - curStep) &
pd.displayCfg.after & " " &
displayedInfo & " -- (" & displayedInfo & " -- (" &
(curPercent * 100).formatFloat(ffDecimal, 2) & "%" (curPercent * 100).formatFloat(ffDecimal, 2) & "%"
if curPercent > 0.05: if curPercent > 0.05:
pd.lastLinePrinted &= ", " line &= ", "
if remTime > 60: if remTime > 60:
pd.lastLinePrinted &= $floor(remTime / 60).int & "m " line &= $floor(remTime / 60).int & "m "
pd.lastLinePrinted &= $ceil(remTime mod 60) & "s" line &= $ceil(remTime mod 60) & "s"
pd.lastLinePrinted &= ")" line &= ")"
line &= spaces(max(pd.width - line.len, 0))
pd.sout.write(pd.lastLinePrinted) pd.sout.write(line)
pd.lastStep = curStep pd.lastStep = curStep
pd.sout.flushFile pd.sout.flushFile
proc erase*(pd: Progress): void = proc erase*(pd: Progress): void =
pd.sout.write('\b'.repeat(pd.lastLinePrinted.len)) pd.sout.write('\b'.repeat(pd.width))
pd.sout.write(' '.repeat(pd.lastLinePrinted.len)) pd.sout.write(' '.repeat(pd.width))
pd.sout.write('\b'.repeat(pd.lastLinePrinted.len)) pd.sout.write('\b'.repeat(pd.width))
pd.lastLinePrinted = ""

8
src/test/nim/test.nim Normal file
View File

@ -0,0 +1,8 @@
import std/os
import ../../main/nim/console_progress
when isMainModule:
let pd = newProgress(100)
for i in 0 .. 100:
pd.updateProgress(i, "step " & $i)
sleep 25