diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c686405 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +build/ +nimcache/ +.gradle/ +*.sw? diff --git a/console_progress.nimble b/console_progress.nimble new file mode 100644 index 0000000..32b6e75 --- /dev/null +++ b/console_progress.nimble @@ -0,0 +1,12 @@ +# Package + +version = "1.0" +author = "Jonathan Bernard" +description = "Utility for writing dynamic progress bars to the console." +license = "BSD" +srcDir = "src/main/nim" + +# Dependencies + +requires "nim >= 0.13.0" + diff --git a/src/main/nim/console_progress.nim b/src/main/nim/console_progress.nim new file mode 100644 index 0000000..dd2b903 --- /dev/null +++ b/src/main/nim/console_progress.nim @@ -0,0 +1,68 @@ +import strutils, times, math + +type Progress* = ref object of RootObj + sout: File + lastStep, maxSteps: int + startTime: float + lastLinePrinted, lastInfo: string + maxValue: BiggestInt + +proc getMax*(pd: Progress): BiggestInt = + return pd.maxValue + +proc setMax*(pd: Progress, maxValue: BiggestInt) = + pd.maxValue = max(maxValue, 1) + +proc newProgress*(sout: File, maxValue: BiggestInt): Progress = + return Progress(sout: sout, + startTime: cpuTime(), + lastStep: 0, + lastLinePrinted: "", + maxValue: maxValue, + maxSteps: 30) + +proc updateProgress*(pd: Progress, newValue: BiggestInt, info: string): void = + + # Calculate progress + let value = min(newValue, pd.maxValue) + let curStep = floor((value.BiggestFloat / pd.maxValue.BiggestFloat) * pd.maxSteps.float).int + let curPercent = value.BiggestFloat / pd.maxValue.BiggestFloat + + if info == pd.lastInfo and curStep == pd.lastStep: return + + let curTime = cpuTime() + let remTime = ((curTime / curPercent) - curTime) * 1000 + let displayedSteps = max(curStep - 1, 0) + + pd.lastInfo = info + var displayedInfo = info + if displayedInfo.len > 16: displayedInfo = info[0..15] + if displayedInfo.len < 16: + displayedInfo = displayedInfo & ' '.repeat(16 - displayedInfo.len) + + pd.sout.write('\b'.repeat(pd.lastLinePrinted.len)) + + pd.lastLinePrinted = + '='.repeat(displayedSteps) & (if curStep > 0: "0" else: "") & + '-'.repeat(pd.maxSteps - curStep) & " " & + displayedInfo & " -- (" & + (curPercent * 100).formatFloat(ffDecimal, 2) & "%" + + if curPercent > 0.05: + pd.lastLinePrinted &= ", " + if remTime > 60: + pd.lastLinePrinted &= $floor(remTime / 60).int & "m " + pd.lastLinePrinted &= $ceil(remTime mod 60) & "s" + + pd.lastLinePrinted &= ")" + + pd.sout.write(pd.lastLinePrinted) + pd.lastStep = curStep + + pd.sout.flushFile + +proc erase*(pd: Progress): void = + pd.sout.write('\b'.repeat(pd.lastLinePrinted.len)) + pd.sout.write(' '.repeat(pd.lastLinePrinted.len)) + pd.sout.write('\b'.repeat(pd.lastLinePrinted.len)) + pd.lastLinePrinted = ""