or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

ask.mdgetopt.mdindex.mdprogress-bar.mdread.mdreadLine.md

progress-bar.mddocs/

0

# Progress Bars

1

2

Visual command-line progress bars with automatic time calculations, customizable display, and ETA predictions for long-running operations.

3

4

## Capabilities

5

6

### ProgressBar Class

7

8

Creates and manages visual progress bars with automatic formatting and time estimation.

9

10

```typescript { .api }

11

/**

12

* Visual progress bar for command-line applications

13

* @param size - Total progress value (default: 100)

14

* @param options - Display and behavior configuration

15

*/

16

class ProgressBar {

17

constructor(

18

size?: number,

19

options?: {

20

/** Increment size for each tick() call (default: 1) */

21

tickSize?: number;

22

/** Suppress all output (default: false) */

23

silent?: boolean;

24

/** Terminal width for bar formatting (default: process.stdout.columns || 70) */

25

terminalWidth?: number;

26

}

27

);

28

29

/** Set current progress to specific value */

30

setValue(value: number): string;

31

32

/** Increment progress by tickSize amount */

33

tick(): string;

34

35

/** Register callback to execute when progress reaches 100% */

36

onFinish(callback: Function): void;

37

38

/** Get elapsed time in milliseconds since creation */

39

getEllapsed(): number;

40

41

/** Get estimated remaining time in milliseconds */

42

getRemaining(): number;

43

44

/** Render current progress bar and return display string */

45

print(): string;

46

47

/** Write text to stdout (respects silent mode) */

48

write(text: string): void;

49

}

50

```

51

52

**Usage Examples:**

53

54

```typescript

55

import { ProgressBar } from "stdio";

56

57

// Basic progress bar

58

const progress = new ProgressBar(100);

59

for (let i = 0; i <= 100; i++) {

60

progress.setValue(i);

61

await delay(50); // Simulate work

62

}

63

64

// Using tick() for incremental progress

65

const progress = new ProgressBar(1000, { tickSize: 10 });

66

while (progress.value < progress.size) {

67

await processItem();

68

progress.tick(); // Increment by 10

69

}

70

71

// Custom configuration

72

const progress = new ProgressBar(50, {

73

tickSize: 2,

74

silent: false,

75

terminalWidth: 80

76

});

77

78

// With completion callback

79

const progress = new ProgressBar(100);

80

progress.onFinish(() => {

81

console.log('\nProcessing complete!');

82

});

83

84

for (let i = 0; i <= 100; i++) {

85

progress.setValue(i);

86

await simulateWork();

87

}

88

// Callback executes automatically when setValue(100) is called

89

90

// File processing example

91

import { createReadStream } from 'fs';

92

import { stat } from 'fs/promises';

93

94

async function processLargeFile(filename: string) {

95

const stats = await stat(filename);

96

const progress = new ProgressBar(stats.size);

97

98

const stream = createReadStream(filename);

99

let bytesProcessed = 0;

100

101

stream.on('data', (chunk) => {

102

bytesProcessed += chunk.length;

103

progress.setValue(bytesProcessed);

104

});

105

106

stream.on('end', () => {

107

console.log('\nFile processing complete!');

108

});

109

}

110

```

111

112

### Progress Display Format

113

114

Progress bars automatically format with time information and ETA:

115

116

```

117

00:01:23 45% [##############################·····················] ETA 00:01:52

118

```

119

120

**Display Components:**

121

- **Elapsed Time**: `00:01:23` - Time since progress started

122

- **Percentage**: `45%` - Current completion percentage

123

- **Visual Bar**: `[###···]` - Visual representation with `#` for completed, `·` for remaining

124

- **ETA**: `00:01:52` - Estimated time remaining

125

126

### Constructor Options

127

128

Comprehensive configuration for progress bar behavior and appearance.

129

130

```typescript { .api }

131

interface ProgressBarOptions {

132

/**

133

* Increment size for tick() calls (default: 1)

134

* Determines how much progress increases with each tick()

135

*/

136

tickSize?: number;

137

138

/**

139

* Suppress all output (default: false)

140

* When true, progress bar is tracked but not displayed

141

*/

142

silent?: boolean;

143

144

/**

145

* Terminal width for formatting (default: process.stdout.columns || 70)

146

* Controls total width of progress bar display

147

*/

148

terminalWidth?: number;

149

}

150

```

151

152

### Instance Properties

153

154

Access to progress bar state and configuration:

155

156

```typescript { .api }

157

class ProgressBar {

158

/** Total progress value (set in constructor) */

159

size: number;

160

161

/** Increment size for tick() calls */

162

tickSize: number;

163

164

/** Current progress value */

165

value: number;

166

167

/** Progress start timestamp */

168

startTime: number;

169

170

/** Recent time estimates for smoothing calculations */

171

lastRemainingTimes: number[];

172

173

/** Output suppression flag */

174

silent: boolean;

175

176

/** Terminal width for formatting */

177

terminalWidth: number;

178

179

/** Completion callback function */

180

callback: Function;

181

}

182

```

183

184

## Advanced Features

185

186

### Time Calculation and ETA

187

188

Sophisticated time estimation with smoothing algorithms:

189

190

```typescript

191

// ETA calculation uses running average of recent processing times

192

const progress = new ProgressBar(1000);

193

194

for (let i = 0; i < 1000; i++) {

195

// Variable processing times are automatically handled

196

const workTime = Math.random() * 100 + 50;

197

await delay(workTime);

198

199

progress.tick();

200

201

// ETA becomes more accurate as more data points are collected

202

console.log(`ETA: ${progress.getRemaining()}ms`);

203

}

204

```

205

206

**Time Features:**

207

- **Elapsed Time**: Accurate tracking from progress start

208

- **ETA Smoothing**: Uses rolling average of last 5 time measurements

209

- **Completion Detection**: ETA shows 0 when progress reaches 100%

210

- **Time Formatting**: Automatic formatting with days, hours, minutes, seconds

211

212

### Visual Customization

213

214

Automatic visual formatting based on terminal width:

215

216

```typescript

217

// Progress bar adapts to available terminal space

218

const progress = new ProgressBar(100, { terminalWidth: 120 });

219

220

// Bar width calculation:

221

// Total width = terminalWidth

222

// Bar width = terminalWidth - elapsed_text - percentage - eta_text

223

// Example: 120 - 8 - 4 - 12 = 96 characters for the actual bar

224

225

// On narrow terminals

226

const narrowProgress = new ProgressBar(100, { terminalWidth: 40 });

227

// Automatically adjusts bar width to fit

228

```

229

230

### Silent Mode and Testing

231

232

Support for background processing and testing scenarios:

233

234

```typescript

235

// Silent mode for background processing

236

const silentProgress = new ProgressBar(100, { silent: true });

237

238

// Progress is tracked but not displayed

239

for (let i = 0; i <= 100; i++) {

240

silentProgress.setValue(i);

241

// No output to terminal

242

}

243

244

// Check progress programmatically

245

console.log(`Final progress: ${silentProgress.value}/${silentProgress.size}`);

246

247

// Testing progress bars

248

function testProgressBar() {

249

const progress = new ProgressBar(10, { silent: true });

250

251

// Verify behavior without terminal output

252

assert.equal(progress.value, 0);

253

254

progress.tick();

255

assert.equal(progress.value, 1);

256

257

progress.setValue(5);

258

assert.equal(progress.value, 5);

259

260

const displayString = progress.print();

261

assert(displayString.includes('50%'));

262

}

263

```

264

265

### Error Handling and Edge Cases

266

267

Robust handling of various scenarios:

268

269

```typescript

270

const progress = new ProgressBar(100);

271

272

// Values beyond size are clamped

273

progress.setValue(150);

274

console.log(progress.value); // 100 (clamped to size)

275

276

// Negative values are handled

277

progress.setValue(-10);

278

console.log(progress.value); // 0 (clamped to minimum)

279

280

// Division by zero protection

281

const zeroProgress = new ProgressBar(0);

282

zeroProgress.setValue(0);

283

// Safely handles edge case without crashing

284

285

// Completion callback safety

286

progress.onFinish(() => {

287

throw new Error('Callback error');

288

});

289

290

try {

291

progress.setValue(100); // Completion triggers callback

292

} catch (error) {

293

console.error('Callback failed:', error.message);

294

// Progress bar itself remains stable

295

}

296

```

297

298

### Integration Patterns

299

300

Common patterns for different use cases:

301

302

**File Upload/Download:**

303

304

```typescript

305

async function uploadFile(file: File, url: string) {

306

const progress = new ProgressBar(file.size);

307

308

const formData = new FormData();

309

formData.append('file', file);

310

311

const response = await fetch(url, {

312

method: 'POST',

313

body: formData

314

});

315

316

// Track upload progress (if supported by fetch implementation)

317

const reader = response.body.getReader();

318

let uploaded = 0;

319

320

while (true) {

321

const { done, value } = await reader.read();

322

if (done) break;

323

324

uploaded += value.length;

325

progress.setValue(uploaded);

326

}

327

328

return response;

329

}

330

```

331

332

**Batch Processing:**

333

334

```typescript

335

async function processBatch<T>(

336

items: T[],

337

processor: (item: T) => Promise<void>

338

): Promise<void> {

339

const progress = new ProgressBar(items.length);

340

341

progress.onFinish(() => {

342

console.log(`\nProcessed ${items.length} items successfully!`);

343

});

344

345

for (let i = 0; i < items.length; i++) {

346

try {

347

await processor(items[i]);

348

progress.tick();

349

} catch (error) {

350

console.error(`\nError processing item ${i}:`, error.message);

351

// Continue with remaining items

352

progress.tick();

353

}

354

}

355

}

356

```

357

358

**Nested Progress:**

359

360

```typescript

361

async function complexOperation() {

362

const mainProgress = new ProgressBar(3);

363

364

console.log('Phase 1: Data Collection');

365

await collectData();

366

mainProgress.tick();

367

368

console.log('Phase 2: Data Processing');

369

await processDataWithProgress(); // This has its own progress bar

370

mainProgress.tick();

371

372

console.log('Phase 3: Results Generation');

373

await generateResults();

374

mainProgress.tick();

375

376

console.log('Operation complete!');

377

}

378

379

async function processDataWithProgress() {

380

const subProgress = new ProgressBar(1000, {

381

terminalWidth: 60 // Smaller bar for sub-operation

382

});

383

384

for (let i = 0; i < 1000; i++) {

385

await processItem(i);

386

subProgress.tick();

387

}

388

}

389

```

390

391

## Constants

392

393

```typescript { .api }

394

/** Default terminal width when process.stdout.columns is unavailable */

395

const DEFAULT_TERMINAL_WIDTH = 70;

396

```