diff --git a/index.d.ts b/index.d.ts index f2006f3..c7fba81 100644 --- a/index.d.ts +++ b/index.d.ts @@ -24,6 +24,11 @@ export type Options = Readonly<{ */ text?: string; + /** + * Text to display before the spinner. + */ + prefixText?: string; + /** * Name of one of the provided spinners. See [`example.js`](https://github.com/BendingBender/ora/blob/master/example.js) in this repo if you want to test out different spinners. On Windows, it will always use the line spinner as the Windows command-line doesn't have proper Unicode support. * @@ -114,9 +119,14 @@ export type PersistOptions = Readonly<{ symbol?: string; /** - * Text to be persisted. Default: Current text. + * Text to be persisted after the symbol. Default: Current `text`. */ text?: string; + + /** + * Text to be persisted before the symbol. Default: Current `prefixText`. + */ + prefixText?: string; }>; export interface Ora { @@ -126,9 +136,14 @@ export interface Ora { readonly isSpinning: boolean; /** - * Change the text. + * Change the text after the spinner. */ text: string; + + /** + * Change the text before the spinner. + */ + prefixText: string; /** * Change the spinner color. diff --git a/index.js b/index.js index 3cbfe5f..ba1da41 100644 --- a/index.js +++ b/index.js @@ -7,6 +7,7 @@ const stripAnsi = require('strip-ansi'); const wcwidth = require('wcwidth'); const TEXT = Symbol('text'); +const PREFIX_TEXT = Symbol('prefixText'); class Ora { constructor(options) { @@ -33,6 +34,7 @@ class Ora { // Set *after* `this.stream` this.text = this.options.text; + this.prefixText = this.options.prefixText; this.linesToClear = 0; this.indent = this.options.indent; } @@ -78,18 +80,32 @@ class Ora { return this[TEXT]; } + get prefixText() { + return this[PREFIX_TEXT]; + } + get isSpinning() { return this.id !== null; } - set text(value) { - this[TEXT] = value; + updateLineCount() { const columns = this.stream.columns || 80; - this.lineCount = stripAnsi('--' + value).split('\n').reduce((count, line) => { + const fullPrefixText = (typeof this[PREFIX_TEXT] === 'string') ? this[PREFIX_TEXT] + '-' : ''; + this.lineCount = stripAnsi(fullPrefixText + '--' + this[TEXT]).split('\n').reduce((count, line) => { return count + Math.max(1, Math.ceil(wcwidth(line) / columns)); }, 0); } + set text(value) { + this[TEXT] = value; + this.updateLineCount(); + } + + set prefixText(value) { + this[PREFIX_TEXT] = value; + this.updateLineCount(); + } + frame() { const {frames} = this.spinner; let frame = frames[this.frameIndex]; @@ -99,8 +115,10 @@ class Ora { } this.frameIndex = ++this.frameIndex % frames.length; + const fullPrefixText = typeof this.prefixText === 'string' ? this.prefixText + ' ' : ''; + const fullText = typeof this.text === 'string' ? ' ' + this.text : ''; - return frame + ' ' + this.text; + return fullPrefixText + frame + fullText; } clear() { @@ -187,8 +205,13 @@ class Ora { } stopAndPersist(options = {}) { + const prefixText = options.prefixText || this.prefixText; + const fullPrefixText = (typeof prefixText === 'string') ? prefixText + ' ' : ''; + const text = options.text || this.text; + const fullText = (typeof text === 'string') ? ' ' + text : ''; + this.stop(); - this.stream.write(`${options.symbol || ' '} ${options.text || this.text}\n`); + this.stream.write(`${fullPrefixText}${options.symbol || ' '}${fullText}n`); return this; } diff --git a/index.test-d.ts b/index.test-d.ts index 21468b1..af7f1f8 100644 --- a/index.test-d.ts +++ b/index.test-d.ts @@ -4,6 +4,7 @@ import ora, {promise} from '.'; const spinner = ora('Loading unicorns'); ora({text: 'Loading unicorns'}); +ora({prefixText: 'Loading unicorns'}); ora({spinner: 'squish'}); ora({spinner: {frames: ['-', '+', '-']}}); ora({spinner: {interval: 80, frames: ['-', '+', '-']}}); @@ -34,6 +35,7 @@ spinner.info('info foo'); spinner.stopAndPersist(); spinner.stopAndPersist({text: 'all done'}); spinner.stopAndPersist({symbol: '@', text: 'all done'}); +spinner.stopAndPersist({prefixText: 'all done'}); spinner.clear(); spinner.render(); spinner.frame(); diff --git a/readme.md b/readme.md index e0353ec..154b112 100644 --- a/readme.md +++ b/readme.md @@ -50,6 +50,12 @@ Type: `string` Text to display after the spinner. +##### prefixText + +Type: `string` + +Text to display before the spinner. + ##### spinner Type: `string` `Object`
@@ -162,9 +168,16 @@ Symbol to replace the spinner with. ###### text Type: `string`
-Default: Current text +Default: Current `text` + +Text to be persisted after the symbol + +###### prefixText + +Type: `string`
+Default: Current `prefixText` -Text to be persisted. +Text to be persisted before the symbol. @@ -182,7 +195,11 @@ Get a new frame. #### .text -Change the text. +Change the text after the spinner. + +#### .prefixText + +Change the text before the spinner. #### .color diff --git a/test.js b/test.js index 579b4aa..4ccab15 100644 --- a/test.js +++ b/test.js @@ -235,6 +235,15 @@ test('erases wrapped lines', t => { t.is(clearedLines, 3); t.is(cursorAtRow, -2); + spinner.clear(); + reset(); + spinner.prefixText = 'foo\n'; + spinner.text = '\nbar'; + spinner.render(); + spinner.render(); + t.is(clearedLines, 3); // Cleared 'foo\n\nbar' + t.is(cursorAtRow, -2); + spinner.stop(); }); @@ -304,3 +313,11 @@ test('indent option throws', t => { spinner.indent = -1; }, 'The `indent` option must be an integer from 0 and up'); }); + +test('.stopAndPersist() with prefixText', macro, spinner => { + spinner.stopAndPersist({symbol: '@', text: 'foo'}); +}, /bar @ foo/, {prefixText: 'bar'}); + +test('.stopAndPersist() with manual prefixText', macro, spinner => { + spinner.stopAndPersist({symbol: '@', prefixText: 'baz', text: 'foo'}); +}, /baz @ foo/, {prefixText: 'bar'});