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

[Feature] Added concurrent info for single progress bars #148

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ node_modules*
.tmp*
intern_*
dev.js
yarn-error.log
yarn-error.log
.DS_Store
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ Features
* Preset/Theme support
* Custom bar formatters (via callback)
* Logging during multibar operation
* Concurrent updatable progress information below progressbar

Usage
------------
Expand Down Expand Up @@ -160,6 +161,28 @@ Note: you may want to increase `etaBuffer` size - otherwise it can cause `INF` e
<instance>.updateETA();
```

### ::setConcurrentInfo()

Sets the text that is written below the progress bar that can be updated while the process is continuing.

For example, the text could track which file is currently being downloaded during a multi-file synchronous download process.

```js
const currentFile = filenames[i];
<instance>.setConcurrentInfo(` --> Downloading ${currentFile}...`);
```

Concurrent Info example:

![](assets/concurrent-info.png)

### ::clearCurrentInfo()

Clears any concurrent text written below the progress bar.

```js
<instance>.clearConcurrentInfo();
```

Multi Bar Mode
-----------------------------------
Expand Down
Binary file added assets/concurrent-info.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 36 additions & 0 deletions examples/example-concurrent-info.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
const cli_progress = require('../cli-progress');

// Generate random file names using random hexadecimal names
const random_file_names = Array(10).fill(0).map(() =>
Math.floor(Math.random() * Math.pow(16, 6)).toString(16) + '.txt'
);

const bar = new cli_progress.Bar({
format: 'Files [{bar}] | {percentage}% | {value}/{total}',
hideCursor: true,
barCompleteChar: '\u2588',
barIncompleteChar: '\u2591',
stopOnComplete: true,

// If clear on complete then both bar and info are cleared
// clearOnComplete: true,

// forceRedraw: true
});

console.log('Downloading files..');
bar.start(200, 0);

const timer = setInterval(() => {
if (bar.value < bar.total) {
bar.increment();

const current_file = random_file_names[Math.floor(bar.value / 20)];
bar.setConcurrentInfo(` --> Downloading ${current_file}...`);
}

if (!bar.isActive) {
clearInterval(timer);
console.log('Download complete!\n');
}
}, 15);
63 changes: 62 additions & 1 deletion lib/generic-bar.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,25 @@ module.exports = class GenericBar extends _EventEmitter{

// use default formatter or custom one ?
this.formatter = (typeof this.options.format === 'function') ? this.options.format : _formatter;

/**
* Whether the progress bar should be able to show concurrent info or not.
* E.g. In multibars, each bar should not be able to have concurrent text
* @type {boolean}
*/
this.allowConcurrentInfo = this.options.allowConcurrentInfo;

/**
* The information to show below progress bar
* @type {string | null}
*/
this.concurrentInfo = null;

/**
* The concurrent information has changed and should be rerendered next render
* @type {boolean}
*/
this.concurrentInfoUpdated = false;
}

// internal render function
Expand Down Expand Up @@ -77,7 +96,7 @@ module.exports = class GenericBar extends _EventEmitter{
|| (this.options.noTTYOutput && !this.terminal.isTTY());

// string changed ? only trigger redraw on change!
if (forceRedraw || this.lastDrawnString != s){
if (forceRedraw || this.lastDrawnString != s || this.concurrentInfoUpdated) {
// trigger event
this.emit('redraw-pre');

Expand All @@ -93,6 +112,22 @@ module.exports = class GenericBar extends _EventEmitter{
// store string
this.lastDrawnString = s;

// check if concurrent text needs to be rendered
if (this.concurrentInfo !== null) {
// reset cursor to start of next line
this.terminal.cursorRelative(-s.length, 1);

// write concurrent info text
this.terminal.write(this.concurrentInfo);
this.terminal.clearRight();

// reset cursor to previous line
this.terminal.cursorRelative(0, -1);

// concurrent info is now up to date
this.concurrentInfoUpdated = false;
}

// set last redraw time
this.lastRedraw = Date.now();

Expand Down Expand Up @@ -231,4 +266,30 @@ module.exports = class GenericBar extends _EventEmitter{
// add new value; recalculate eta
this.eta.update(Date.now(), this.value, this.total);
}

/**
* Sets the information that is given as additional concurrent information
* below the progress bar. It is cleared once the bar completes.
* @param {string} text The info shown below the progress bar
*/
setConcurrentInfo(text) {
if (!this.allowConcurrentInfo) {
return;
}

this.concurrentInfoUpdated = this.concurrentInfo !== text;
this.concurrentInfo = text;
}

/**
* Clears the additional concurrent information.
*/
clearConcurrentInfo() {
if (!this.allowConcurrentInfo) {
return;
}

this.concurrentInfoUpdated = this.concurrentInfo !== '';
this.concurrentInfo = '';
}
}
7 changes: 5 additions & 2 deletions lib/multi-bar.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,12 @@ module.exports = class MultiBar extends _EventEmitter{
// global options
this.options,

// terminal instance
{
terminal: this.terminal
// terminal instance
terminal: this.terminal,

// concurrent text in multibars is not defined behaviour
allowConcurrentInfo: false
},

// overrides
Expand Down
2 changes: 2 additions & 0 deletions lib/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ module.exports = {
// autopadding character - empty in case autopadding is disabled
options.autopaddingChar = options.autopadding ? mergeOption(options.autopaddingChar, ' ') : '';

options.allowConcurrentInfo = 'allowConcurrentInfo' in options ? options.allowConcurrentInfo : true;

return options;
}
};
9 changes: 7 additions & 2 deletions lib/single-bar.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,15 @@ module.exports = class SingleBar extends _GenericBar{

// clear line on complete ?
if (this.options.clearOnComplete){
// clear progress bar (And any information below) and remain on same line
this.terminal.cursorTo(0, null);
this.terminal.clearBottom();
} else if (this.concurrentInfo) {
// clear the concurrent information and begin on new line
this.terminal.cursorRelative(0, 1);
this.terminal.clearLine();
}else{
// new line on complete
} else {
// start on next line
this.terminal.newline();
}
}
Expand Down