0
# User Interface Control
1
2
Terminal UI management including show/hide prompt, logging, user interaction through prompts, and advanced UI redraw functionality.
3
4
## Capabilities
5
6
### Show Interface
7
8
Shows the Vorpal prompt in the terminal.
9
10
```javascript { .api }
11
/**
12
* Shows the vorpal prompt in the terminal
13
* @returns Vorpal instance for chaining
14
*/
15
function show(): Vorpal;
16
```
17
18
**Usage Example:**
19
20
```javascript
21
const vorpal = require('vorpal')();
22
23
// Setup commands first
24
vorpal
25
.command('hello', 'Says hello')
26
.action(function(args, callback) {
27
this.log('Hello World!');
28
callback();
29
});
30
31
// Show the interactive prompt
32
vorpal
33
.delimiter('myapp$')
34
.show();
35
```
36
37
### Hide Interface
38
39
Hides the Vorpal prompt from the terminal.
40
41
```javascript { .api }
42
/**
43
* Hides the vorpal prompt from the terminal
44
* @returns Vorpal instance for chaining
45
*/
46
function hide(): Vorpal;
47
```
48
49
**Usage Example:**
50
51
```javascript
52
const vorpal = require('vorpal')();
53
54
// Show the prompt initially
55
vorpal.show();
56
57
// Later, hide it during some operation
58
vorpal.hide();
59
60
// Processing something in background...
61
setTimeout(() => {
62
console.log('Background task completed');
63
// Show the prompt again
64
vorpal.show();
65
}, 2000);
66
```
67
68
### Logging
69
70
Logs output to the console through Vorpal's logging system.
71
72
```javascript { .api }
73
/**
74
* Logs output to console through Vorpal's logging system
75
* @param args - Arguments to log (same as console.log)
76
* @returns Vorpal instance for chaining
77
*/
78
function log(...args: any[]): Vorpal;
79
```
80
81
**Usage Examples:**
82
83
```javascript
84
const vorpal = require('vorpal')();
85
86
// Basic logging
87
vorpal.log('Hello, world!');
88
89
// Multiple arguments
90
vorpal.log('User:', 'john', 'Age:', 25);
91
92
// Logging objects
93
vorpal.log('Config:', { port: 3000, env: 'development' });
94
95
// In command actions
96
vorpal
97
.command('status', 'Shows application status')
98
.action(function(args, callback) {
99
// Use this.log within command context
100
this.log('Application is running');
101
this.log('Status: OK');
102
103
// Or use vorpal.log from outside
104
callback();
105
});
106
```
107
108
### User Prompts
109
110
Prompts the user for input with configurable options.
111
112
```javascript { .api }
113
/**
114
* Prompts user for input
115
* @param options - Prompt configuration object or array of prompts
116
* @param userCallback - Optional callback function (if omitted, returns Promise)
117
* @returns Promise when no callback provided
118
*/
119
function prompt(options?: PromptOptions | PromptOptions[], userCallback?: (result: any) => void): Promise<any>;
120
121
interface PromptOptions {
122
type?: 'input' | 'password' | 'confirm' | 'list' | 'rawlist' | 'expand' | 'checkbox' | 'editor';
123
name?: string;
124
message?: string;
125
default?: any;
126
choices?: string[] | ChoiceOption[];
127
validate?: (input: any) => boolean | string;
128
filter?: (input: any) => any;
129
when?: boolean | ((answers: any) => boolean);
130
}
131
132
interface ChoiceOption {
133
name: string;
134
value?: any;
135
short?: string;
136
}
137
```
138
139
**Usage Examples:**
140
141
```javascript
142
const vorpal = require('vorpal')();
143
144
// Single input prompt with callback
145
vorpal.prompt({
146
type: 'input',
147
name: 'username',
148
message: 'Enter your username:',
149
default: 'guest'
150
}, function(result) {
151
console.log('Username:', result.username);
152
});
153
154
// Promise-based prompting
155
vorpal.prompt({
156
type: 'password',
157
name: 'password',
158
message: 'Enter your password:'
159
})
160
.then(function(result) {
161
console.log('Password length:', result.password.length);
162
});
163
164
// Multiple prompts
165
vorpal.prompt([
166
{
167
type: 'input',
168
name: 'name',
169
message: 'What is your name?'
170
},
171
{
172
type: 'list',
173
name: 'color',
174
message: 'What is your favorite color?',
175
choices: ['Red', 'Blue', 'Green', 'Yellow']
176
},
177
{
178
type: 'confirm',
179
name: 'confirmed',
180
message: 'Are you sure?',
181
default: true
182
}
183
])
184
.then(function(answers) {
185
console.log('Name:', answers.name);
186
console.log('Color:', answers.color);
187
console.log('Confirmed:', answers.confirmed);
188
});
189
190
// Validation example
191
vorpal.prompt({
192
type: 'input',
193
name: 'email',
194
message: 'Enter your email:',
195
validate: function(input) {
196
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
197
if (!emailRegex.test(input)) {
198
return 'Please enter a valid email address';
199
}
200
return true;
201
}
202
})
203
.then(function(result) {
204
console.log('Valid email:', result.email);
205
});
206
207
// Using within command actions
208
vorpal
209
.command('setup', 'Interactive setup')
210
.action(function(args, callback) {
211
const self = this;
212
213
self.prompt([
214
{
215
type: 'input',
216
name: 'appName',
217
message: 'Application name:'
218
},
219
{
220
type: 'list',
221
name: 'environment',
222
message: 'Select environment:',
223
choices: ['development', 'staging', 'production']
224
}
225
], function(result) {
226
self.log(`Setting up ${result.appName} for ${result.environment}`);
227
callback();
228
});
229
});
230
```
231
232
### Conditional Prompts
233
234
Advanced prompting with conditional logic:
235
236
```javascript
237
vorpal.prompt([
238
{
239
type: 'confirm',
240
name: 'needsDatabase',
241
message: 'Do you need a database?'
242
},
243
{
244
type: 'list',
245
name: 'databaseType',
246
message: 'Select database type:',
247
choices: ['MySQL', 'PostgreSQL', 'MongoDB', 'SQLite'],
248
when: function(answers) {
249
return answers.needsDatabase;
250
}
251
},
252
{
253
type: 'input',
254
name: 'databaseUrl',
255
message: 'Database connection URL:',
256
when: function(answers) {
257
return answers.needsDatabase;
258
},
259
validate: function(input) {
260
if (!input.trim()) {
261
return 'Database URL is required';
262
}
263
return true;
264
}
265
}
266
])
267
.then(function(answers) {
268
if (answers.needsDatabase) {
269
console.log(`Using ${answers.databaseType} at ${answers.databaseUrl}`);
270
} else {
271
console.log('No database configured');
272
}
273
});
274
```
275
276
## Complete UI Example
277
278
```javascript
279
const vorpal = require('vorpal')();
280
281
// Setup interactive CLI with rich UI
282
vorpal
283
.delimiter('myapp$')
284
.banner('Welcome to My Application v1.0.0')
285
.command('configure', 'Interactive configuration')
286
.action(function(args, callback) {
287
const self = this;
288
289
self.log('Starting configuration wizard...');
290
291
self.prompt([
292
{
293
type: 'input',
294
name: 'name',
295
message: 'Project name:',
296
default: 'my-project'
297
},
298
{
299
type: 'list',
300
name: 'framework',
301
message: 'Select framework:',
302
choices: [
303
{ name: 'Express.js', value: 'express' },
304
{ name: 'Koa.js', value: 'koa' },
305
{ name: 'Fastify', value: 'fastify' }
306
]
307
},
308
{
309
type: 'checkbox',
310
name: 'features',
311
message: 'Select features:',
312
choices: [
313
'Authentication',
314
'Database',
315
'Caching',
316
'Logging',
317
'Testing'
318
]
319
},
320
{
321
type: 'confirm',
322
name: 'proceed',
323
message: 'Proceed with configuration?',
324
default: true
325
}
326
], function(result) {
327
if (result.proceed) {
328
self.log('Configuration saved:');
329
self.log('- Name:', result.name);
330
self.log('- Framework:', result.framework);
331
self.log('- Features:', result.features.join(', '));
332
} else {
333
self.log('Configuration cancelled');
334
}
335
callback();
336
});
337
});
338
339
// Show the interface
340
vorpal.show();
341
```
342
343
## Advanced UI Methods
344
345
### Prompt Pause and Resume
346
347
Controls prompt state for complex user interactions.
348
349
```javascript { .api }
350
/**
351
* Pauses active prompt, returning the value of what had been typed so far
352
* @returns Current prompt input string or false if no active prompt
353
*/
354
function pause(): string | false;
355
356
/**
357
* Resumes active prompt with optional text to fill prompt with
358
* @param val - Optional text to fill prompt with on resume
359
* @returns UI instance for chaining
360
*/
361
function resume(val?: string): UI;
362
```
363
364
**Usage Example:**
365
366
```javascript
367
const vorpal = require('vorpal')();
368
369
vorpal
370
.command('interactive', 'Interactive command with pause/resume')
371
.action(function(args, callback) {
372
const self = this;
373
374
// Start a prompt
375
self.prompt({
376
type: 'input',
377
name: 'data',
378
message: 'Enter some data (will be paused):'
379
}, function(result) {
380
self.log('Final result:', result.data);
381
callback();
382
});
383
384
// Pause the prompt after 2 seconds
385
setTimeout(() => {
386
const currentInput = vorpal.ui.pause();
387
self.log('Prompt paused. Current input:', currentInput);
388
389
// Do some processing...
390
setTimeout(() => {
391
self.log('Resuming prompt...');
392
vorpal.ui.resume(currentInput + ' [processed]');
393
}, 1000);
394
}, 2000);
395
});
396
```
397
398
### Prompt Cancellation
399
400
Cancels the currently active prompt.
401
402
```javascript { .api }
403
/**
404
* Cancels the active prompt
405
* @returns UI instance for chaining
406
*/
407
function cancel(): UI;
408
```
409
410
**Usage Example:**
411
412
```javascript
413
const vorpal = require('vorpal')();
414
415
vorpal
416
.command('cancelable', 'A command with cancelable prompt')
417
.action(function(args, callback) {
418
const self = this;
419
420
// Start a prompt
421
self.prompt({
422
type: 'input',
423
name: 'data',
424
message: 'Enter data (will auto-cancel in 5s):'
425
})
426
.then(result => {
427
self.log('Data entered:', result.data);
428
})
429
.catch(err => {
430
self.log('Prompt was cancelled');
431
})
432
.finally(() => {
433
callback();
434
});
435
436
// Auto-cancel after 5 seconds
437
setTimeout(() => {
438
self.log('Auto-cancelling prompt...');
439
vorpal.ui.cancel();
440
}, 5000);
441
});
442
```
443
444
### UI Redraw Methods
445
446
Advanced terminal output control for dynamic content updates.
447
448
```javascript { .api }
449
/**
450
* Writes over existing logging, useful for progress indicators
451
* @param str - Content to write over existing output
452
* @returns UI instance for chaining
453
*/
454
function redraw(str: string): UI;
455
456
/**
457
* Clears all redraw content permanently
458
* @returns UI instance for chaining
459
*/
460
function redraw.clear(): UI;
461
462
/**
463
* Makes current redraw content permanent
464
* @returns UI instance for chaining
465
*/
466
function redraw.done(): UI;
467
```
468
469
**Usage Examples:**
470
471
```javascript
472
const vorpal = require('vorpal')();
473
474
vorpal
475
.command('progress', 'Shows a progress indicator')
476
.action(function(args, callback) {
477
const self = this;
478
let progress = 0;
479
const total = 100;
480
481
const interval = setInterval(() => {
482
progress += 10;
483
const percentage = Math.round((progress / total) * 100);
484
const bar = '█'.repeat(Math.floor(percentage / 5)) +
485
'░'.repeat(20 - Math.floor(percentage / 5));
486
487
// Update the same line with progress
488
vorpal.ui.redraw(`Progress: [${bar}] ${percentage}%`);
489
490
if (progress >= total) {
491
clearInterval(interval);
492
// Make the final progress permanent
493
vorpal.ui.redraw.done();
494
self.log('Process completed!');
495
callback();
496
}
497
}, 200);
498
});
499
500
vorpal
501
.command('loading', 'Shows a loading spinner')
502
.action(function(args, callback) {
503
const self = this;
504
const spinner = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
505
let i = 0;
506
507
const interval = setInterval(() => {
508
vorpal.ui.redraw(`Loading ${spinner[i % spinner.length]} Please wait...`);
509
i++;
510
}, 100);
511
512
// Simulate work
513
setTimeout(() => {
514
clearInterval(interval);
515
// Clear the loading message
516
vorpal.ui.redraw.clear();
517
self.log('Loading completed!');
518
callback();
519
}, 3000);
520
});
521
522
vorpal
523
.command('live-data', 'Shows live updating data')
524
.action(function(args, callback) {
525
const self = this;
526
let counter = 0;
527
528
self.log('Starting live data feed (Ctrl+C to stop):');
529
530
const interval = setInterval(() => {
531
const timestamp = new Date().toLocaleTimeString();
532
const data = {
533
counter: ++counter,
534
timestamp: timestamp,
535
random: Math.floor(Math.random() * 1000)
536
};
537
538
// Update the display with current data
539
vorpal.ui.redraw(JSON.stringify(data, null, 2));
540
}, 1000);
541
542
// Handle cancellation
543
const originalCancel = self.cancel;
544
self.cancel = function() {
545
clearInterval(interval);
546
vorpal.ui.redraw.clear();
547
self.log('Live data feed stopped');
548
if (originalCancel) originalCancel.call(self);
549
callback();
550
};
551
552
// Auto-stop after 10 seconds for demo
553
setTimeout(() => {
554
clearInterval(interval);
555
vorpal.ui.redraw.done(); // Keep the last data visible
556
self.log('Live data feed ended');
557
callback();
558
}, 10000);
559
});
560
```
561
562
### Dynamic Status Display
563
564
Advanced example combining multiple UI methods:
565
566
```javascript
567
const vorpal = require('vorpal')();
568
569
vorpal
570
.command('system-monitor', 'Shows real-time system information')
571
.action(function(args, callback) {
572
const self = this;
573
const os = require('os');
574
575
self.log('System Monitor Started (press any key to stop)');
576
577
let monitoring = true;
578
const interval = setInterval(() => {
579
if (!monitoring) return;
580
581
const cpuUsage = process.cpuUsage();
582
const memUsage = process.memoryUsage();
583
const uptime = process.uptime();
584
585
const display = [
586
'=== System Monitor ===',
587
`Uptime: ${Math.floor(uptime)}s`,
588
`CPU User: ${(cpuUsage.user / 1000000).toFixed(2)}ms`,
589
`CPU System: ${(cpuUsage.system / 1000000).toFixed(2)}ms`,
590
`Memory RSS: ${(memUsage.rss / 1024 / 1024).toFixed(2)}MB`,
591
`Memory Heap: ${(memUsage.heapUsed / 1024 / 1024).toFixed(2)}MB`,
592
`Memory External: ${(memUsage.external / 1024 / 1024).toFixed(2)}MB`,
593
'=====================',
594
'Press any key to stop monitoring...'
595
].join('\n');
596
597
vorpal.ui.redraw(display);
598
}, 1000);
599
600
// Wait for any key press
601
process.stdin.setRawMode(true);
602
process.stdin.resume();
603
process.stdin.once('data', () => {
604
monitoring = false;
605
clearInterval(interval);
606
607
process.stdin.setRawMode(false);
608
process.stdin.pause();
609
610
vorpal.ui.redraw.clear();
611
self.log('System monitoring stopped');
612
callback();
613
});
614
});
615
```
616
617
## UI Best Practices
618
619
### Responsive Prompts
620
621
Handle different terminal sizes and capabilities:
622
623
```javascript
624
vorpal
625
.command('responsive-ui', 'Shows responsive UI elements')
626
.action(function(args, callback) {
627
const self = this;
628
const terminalWidth = process.stdout.columns || 80;
629
const narrow = terminalWidth < 60;
630
631
if (narrow) {
632
// Simplified UI for narrow terminals
633
self.prompt([
634
{
635
type: 'input',
636
name: 'name',
637
message: 'Name:'
638
},
639
{
640
type: 'confirm',
641
name: 'proceed',
642
message: 'OK?'
643
}
644
], function(result) {
645
self.log('Done:', result.name);
646
callback();
647
});
648
} else {
649
// Full UI for wider terminals
650
self.prompt([
651
{
652
type: 'input',
653
name: 'fullName',
654
message: 'Please enter your full name:'
655
},
656
{
657
type: 'list',
658
name: 'role',
659
message: 'Select your role:',
660
choices: ['Administrator', 'Developer', 'User', 'Guest']
661
},
662
{
663
type: 'confirm',
664
name: 'proceed',
665
message: 'Proceed with these settings?'
666
}
667
], function(result) {
668
self.log('Configuration complete:');
669
self.log('Name:', result.fullName);
670
self.log('Role:', result.role);
671
callback();
672
});
673
}
674
});
675
```
676
677
### Error Recovery
678
679
Handle UI errors gracefully:
680
681
```javascript
682
vorpal
683
.command('robust-ui', 'UI with error handling')
684
.action(function(args, callback) {
685
const self = this;
686
687
function safePrompt(options, retryCount = 0) {
688
const maxRetries = 3;
689
690
self.prompt(options)
691
.then(result => {
692
self.log('Success:', result);
693
callback();
694
})
695
.catch(err => {
696
if (retryCount < maxRetries) {
697
self.log(`Error occurred, retrying... (${retryCount + 1}/${maxRetries})`);
698
setTimeout(() => {
699
safePrompt(options, retryCount + 1);
700
}, 1000);
701
} else {
702
self.log('Max retries exceeded. Operation failed.');
703
callback(err);
704
}
705
});
706
}
707
708
safePrompt({
709
type: 'input',
710
name: 'data',
711
message: 'Enter data:'
712
});
713
});
714
```