Skip to content

Commit

Permalink
Add suffixText option (#223)
Browse files Browse the repository at this point in the history
  • Loading branch information
tommy-mitchell committed Mar 24, 2023
1 parent 16cc211 commit 2378eaf
Show file tree
Hide file tree
Showing 6 changed files with 153 additions and 14 deletions.
28 changes: 26 additions & 2 deletions example.js
@@ -1,5 +1,6 @@
import process from 'node:process';
import chalk from 'chalk';
import logSymbols from 'log-symbols';
import ora from './index.js';

const spinner = ora({
Expand Down Expand Up @@ -46,7 +47,30 @@ setTimeout(() => {
}, 6000);

setTimeout(() => {
spinner.succeed();
}, 7000);
spinner.prefixText = chalk.dim('[info]');
spinner.spinner = 'dots';
spinner.text = 'Loading with prefix text';
}, 8000);

setTimeout(() => {
spinner.prefixText = '';
spinner.suffixText = chalk.dim('[info]');
spinner.text = 'Loading with suffix text';
}, 10_000);

setTimeout(() => {
spinner.prefixText = chalk.dim('[info]');
spinner.suffixText = chalk.dim('[info]');
spinner.text = 'Loading with prefix and suffix text';
}, 12_000);

setTimeout(() => {
spinner.stopAndPersist({
prefixText: '',
suffixText: '',
symbol: logSymbols.info,
text: 'Stopping with different text!',
});
}, 14_000);

// $ node example.js nameOfSpinner
21 changes: 21 additions & 0 deletions index.d.ts
Expand Up @@ -18,6 +18,8 @@ export type Color =

export type PrefixTextGenerator = () => string;

export type SuffixTextGenerator = () => string;

export interface Options {
/**
Text to display after the spinner.
Expand All @@ -29,6 +31,11 @@ export interface Options {
*/
readonly prefixText?: string | PrefixTextGenerator;

/**
Text or a function that returns text to display after the spinner text. No suffix text will be displayed if set to an empty string.
*/
readonly suffixText?: string | SuffixTextGenerator;

/**
Name of one of the provided spinners. See [`example.js`](https://github.com/BendingBender/ora/blob/main/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.
Expand Down Expand Up @@ -130,6 +137,13 @@ export interface PersistOptions {
Default: Current `prefixText`.
*/
readonly prefixText?: string | PrefixTextGenerator;

/**
Text or a function that returns text to be persisted after the text after the symbol. No suffix text will be displayed if set to an empty string.
Default: Current `suffixText`.
*/
readonly suffixText?: string | SuffixTextGenerator;
}

export interface PromiseOptions<T> extends Options {
Expand Down Expand Up @@ -161,6 +175,13 @@ export interface Ora {
*/
prefixText: string;

/**
Change the text or function that returns text after the spinner text.
No suffix text will be displayed if set to an empty string.
*/
suffixText: string;

/**
Change the spinner color.
*/
Expand Down
45 changes: 40 additions & 5 deletions index.js
Expand Up @@ -24,6 +24,7 @@ class Ora {
#indent;
#text;
#prefixText;
#suffixText;

color;

Expand Down Expand Up @@ -57,6 +58,7 @@ class Ora {
// It's important that these use the public setters.
this.text = this.#options.text;
this.prefixText = this.#options.prefixText;
this.suffixText = this.#options.suffixText;
this.indent = this.#options.indent;

if (process.env.NODE_ENV === 'test') {
Expand Down Expand Up @@ -147,6 +149,15 @@ class Ora {
this.updateLineCount();
}

get suffixText() {
return this.#suffixText;
}

set suffixText(value) {
this.#suffixText = value || '';
this.updateLineCount();
}

get isSpinning() {
return this.#id !== undefined;
}
Expand All @@ -164,12 +175,26 @@ class Ora {
return '';
}

getFullSuffixText(suffixText = this.#suffixText, prefix = ' ') {
if (typeof suffixText === 'string' && suffixText !== '') {
return prefix + suffixText;
}

if (typeof suffixText === 'function') {
return prefix + suffixText();
}

return '';
}

updateLineCount() {
const columns = this.#stream.columns || 80;
const fullPrefixText = this.getFullPrefixText(this.#prefixText, '-');
const fullSuffixText = this.getFullSuffixText(this.#suffixText, '-');
const fullText = ' '.repeat(this.#indent) + fullPrefixText + '--' + this.#text + '--' + fullSuffixText;

this.#lineCount = 0;
for (const line of stripAnsi(' '.repeat(this.#indent) + fullPrefixText + '--' + this.#text).split('\n')) {
for (const line of stripAnsi(fullText).split('\n')) {
this.#lineCount += Math.max(1, Math.ceil(wcwidth(line) / columns));
}
}
Expand Down Expand Up @@ -209,8 +234,9 @@ class Ora {
this.#frameIndex = ++this.#frameIndex % frames.length;
const fullPrefixText = (typeof this.#prefixText === 'string' && this.#prefixText !== '') ? this.#prefixText + ' ' : '';
const fullText = typeof this.text === 'string' ? ' ' + this.text : '';
const fullSuffixText = (typeof this.#suffixText === 'string' && this.#suffixText !== '') ? ' ' + this.#suffixText : '';

return fullPrefixText + frame + fullText;
return fullPrefixText + frame + fullText + fullSuffixText;
}

clear() {
Expand Down Expand Up @@ -328,12 +354,21 @@ class Ora {
return this;
}

const prefixText = options.prefixText || this.#prefixText;
const text = options.text || this.text;
const prefixText = options.prefixText ?? this.#prefixText;
const fullPrefixText = this.getFullPrefixText(prefixText, ' ');

const symbolText = options.symbol ?? ' ';

const text = options.text ?? this.text;
const fullText = (typeof text === 'string') ? ' ' + text : '';

const suffixText = options.suffixText ?? this.#suffixText;
const fullSuffixText = this.getFullSuffixText(suffixText, ' ');

const textToWrite = fullPrefixText + symbolText + fullText + fullSuffixText + '\n';

this.stop();
this.#stream.write(`${this.getFullPrefixText(prefixText, ' ')}${options.symbol || ' '}${fullText}\n`);
this.#stream.write(textToWrite);

return this;
}
Expand Down
4 changes: 4 additions & 0 deletions index.test-d.ts
Expand Up @@ -7,6 +7,8 @@ const spinner = ora('Loading unicorns');
ora({text: 'Loading unicorns'});
ora({prefixText: 'Loading unicorns'});
ora({prefixText: () => 'Loading unicorns dynamically'});
ora({suffixText: 'Loading unicorns'});
ora({suffixText: () => 'Loading unicorns dynamically'});
ora({spinner: 'squish'});
ora({spinner: {frames: ['-', '+', '-']}});
ora({spinner: {interval: 80, frames: ['-', '+', '-']}});
Expand Down Expand Up @@ -40,6 +42,7 @@ spinner.stopAndPersist();
spinner.stopAndPersist({text: 'all done'});
spinner.stopAndPersist({symbol: '@', text: 'all done'});
spinner.stopAndPersist({prefixText: 'all done'});
spinner.stopAndPersist({suffixText: 'all done'});
spinner.clear();
spinner.render();
spinner.frame();
Expand All @@ -58,6 +61,7 @@ void oraPromise(async () => {
}, 'foo');
void oraPromise(async spinner => {
spinner.prefixText = 'foo';
spinner.suffixText = '[loading]';
await resolves;
return 7;
}, {
Expand Down
21 changes: 20 additions & 1 deletion readme.md
Expand Up @@ -50,6 +50,12 @@ Type: `string | () => string`

Text or a function that returns text to display before the spinner. No prefix text will be displayed if set to an empty string.

##### suffixText

Type: `string | () => string`

Text or a function that returns text to display after the spinner text. No suffix text will be displayed if set to an empty string.

##### spinner

Type: `string | object`\
Expand Down Expand Up @@ -142,6 +148,12 @@ Change the text before the spinner.

No prefix text will be displayed if set to an empty string.

#### .suffixText <sup>get/set</sup>

Change the text after the spinner text.

No suffix text will be displayed if set to an empty string.

#### .color <sup>get/set</sup>

Change the spinner color.
Expand Down Expand Up @@ -208,7 +220,7 @@ Symbol to replace the spinner with.
Type: `string`\
Default: Current `'text'`

Text to be persisted after the symbol
Text to be persisted after the symbol.

###### prefixText

Expand All @@ -217,6 +229,13 @@ Default: Current `prefixText`

Text to be persisted before the symbol. No prefix text will be displayed if set to an empty string.

###### suffixText

Type: `string`\
Default: Current `suffixText`

Text to be persisted after the text after the symbol. No suffix text will be displayed if set to an empty string.

<img src="screenshot-2.gif" width="480">

#### .clear()
Expand Down
48 changes: 42 additions & 6 deletions test.js
Expand Up @@ -239,6 +239,16 @@ test('erases wrapped lines', t => {
t.is(clearedLines, 3); // Cleared 'foo\n\nbar'
t.is(cursorAtRow, -2);

spinner.clear();
reset();
spinner.prefixText = 'foo\n';
spinner.text = '\nbar';
spinner.suffixText = '\nbaz';
spinner.render();
spinner.render();
t.is(clearedLines, 4); // Cleared 'foo\n\nbar \nbaz'
t.is(cursorAtRow, -3);

spinner.stop();
});

Expand Down Expand Up @@ -398,6 +408,30 @@ test('.stopAndPersist() with dynamic prefixText', macro, spinner => {
spinner.stopAndPersist({symbol: '&', prefixText: () => 'babeee', text: 'yorkie'});
}, /babeee & yorkie\n$/, {prefixText: () => 'babeee'});

test('.stopAndPersist() with suffixText', macro, spinner => {
spinner.stopAndPersist({symbol: '@', text: 'foo'});
}, /@ foo bar\n$/, {suffixText: 'bar'});

test('.stopAndPersist() with empty suffixText', macro, spinner => {
spinner.stopAndPersist({symbol: '@', text: 'foo'});
}, /@ foo\n$/, {suffixText: ''});

test('.stopAndPersist() with manual suffixText', macro, spinner => {
spinner.stopAndPersist({symbol: '@', suffixText: 'baz', text: 'foo'});
}, /@ foo baz\n$/, {suffixText: 'bar'});

test('.stopAndPersist() with manual empty suffixText', macro, spinner => {
spinner.stopAndPersist({symbol: '@', suffixText: '', text: 'foo'});
}, /@ foo\n$/, {suffixText: 'bar'});

test('.stopAndPersist() with dynamic suffixText', macro, spinner => {
spinner.stopAndPersist({symbol: '&', suffixText: () => 'babeee', text: 'yorkie'});
}, /& yorkie babeee\n$/, {suffixText: () => 'babeee'});

test('.stopAndPersist() with prefixText and suffixText', macro, spinner => {
spinner.stopAndPersist({symbol: '@', text: 'foo'});
}, /bar @ foo baz\n$/, {prefixText: 'bar', suffixText: 'baz'});

// New clear method tests

const currentClearMethod = transFormTTY => {
Expand Down Expand Up @@ -596,21 +630,23 @@ test('new clear method test, erases wrapped lines', t => {
currentOra.clear();
currentOra.prefixText = 'foo\n';
currentOra.text = '\nbar';
currentOra.suffixText = '\nbaz';
currentOra.render();
currentOra.render();

spinner.clear();
spinner.prefixText = 'foo\n';
spinner.text = '\nbar';
spinner.suffixText = '\nbaz';
spinner.render();
spinner.render();
t.is(clearedLines(), 3); // Cleared 'foo\n\nbar'
t.is(cursorAtRow(), -2);
t.is(clearedLines(), 4); // Cleared 'foo\n\nbar \nbaz'
t.is(cursorAtRow(), -3);

const [sequenceString, clearedSequenceString] = transformTTY.getSequenceStrings();
const [frames, clearedFrames] = transformTTY.getFrames();

t.is(sequenceString, 'foo\n - \nbar');
t.is(sequenceString, 'foo\n - \nbar \nbaz');
t.is(sequenceString, clearedSequenceString);

t.deepEqual(clearedFrames, [
Expand All @@ -630,14 +666,14 @@ test('new clear method test, erases wrapped lines', t => {
'- πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„\n'
+ 'πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„πŸ¦„\n'
+ 'foo',
'foo\n - \nbar',
'foo\n - \nbar',
'foo\n - \nbar \nbaz',
'foo\n - \nbar \nbaz',
]);

t.deepEqual(frames, clearedFrames);

const currentClearString = currentClearTTY.toString();
t.is(currentClearString, 'foo\n - \nbar');
t.is(currentClearString, 'foo\n - \nbar \nbaz');

const currentFrames = currentClearTTY.getFrames();
t.deepEqual(frames, currentFrames);
Expand Down

0 comments on commit 2378eaf

Please sign in to comment.