Skip to content

Instantly share code, notes, and snippets.

@andrewthauer
Last active May 27, 2023 13:31
Show Gist options
  • Save andrewthauer/261c916a9b07036c0b04b463ae5e94eb to your computer and use it in GitHub Desktop.
Save andrewthauer/261c916a9b07036c0b04b463ae5e94eb to your computer and use it in GitHub Desktop.
Deno Progress Bar
import { tty } from "https://deno.land/x/cliffy@v0.25.7/ansi/tty.ts";
interface ProgressBarOptions {
label?: string;
total?: number;
width?: number;
}
/**
* A simple progress bar for Deno
* @param options
* - `label` - The label to display before the progress bar
* - `total` - The total number of steps to completion
* - `width` - The width of the progress bar (defaults to the width of the terminal)
* @constructor
* @example
* const bar = new ProgresBar({ label: "Downloading", total: 100 });
* for (let i = 0; i <= 100; i++) {
* bar.update(i);
* await sleep(100);
* }
*/
export class ProgressBar {
private label = "";
private total: number;
private barWidth: number;
private barStart: number;
private barEnd: number;
private pctStart = 0;
private pctLength = "100.0%".length;
private chars = ["░", "▒", "▓", "█"];
private _tty = tty({
stdout: Deno.stdout,
stdin: Deno.stdin,
});
constructor(options?: ProgressBarOptions) {
const columns = Deno.consoleSize().columns;
this.label = options?.label ?? "Progress";
this.total = options?.total ?? 100;
this.pctStart = columns - this.pctLength;
this.barEnd = this.pctStart - 1;
this.barStart = this.label.length + 1;
this.barWidth = options?.width ?? this.barEnd - this.barStart;
}
update(i: number) {
const pct = i / this.total;
const pctText = `${(i / this.total * 100).toFixed(1)}%`.padStart(
this.pctLength,
);
const filled = this.barWidth * pct;
const filledWhole = Math.floor(filled);
const bar = this.chars[this.chars.length - 1].repeat(filledWhole);
const empty = this.chars[0].repeat(
Math.max(0, this.barWidth - filledWhole - 1),
);
const str = `${this.label} ${bar}${empty} ${pctText}`;
this._tty.text(str).cursorLeft();
}
}
const sleep = (ms: number) => {
return new Promise((resolve) => setTimeout(resolve, ms));
};
const loop = async () => {
const pb = new ProgresBar();
for (let i = 0; i < 100; i++) {
await sleep(20);
pb.update(i);
}
};
await loop();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment