Showing Output
Introduction
For creating a more interactive experience for the user, an output from the given task can be shown. Output is a separate entity compared to the title.
Usage
Show Output Through the Task Itself
This will show the output in a small bar that can only show the last output from the task.
new Listr<Ctx>(
[
{
title: 'This task will execute.',
task: async (ctx, task): Promise<void> => {
task.output = 'I will push an output. [0]'
await delay(500)
task.output = 'I will push an output. [1]'
await delay(500)
task.output = 'I will push an output. [2]'
await delay(500)
}
}
],
{ concurrent: false }
)
Passing Data Through an Observable or a Stream
Since observables and streams are supported they can also be used to generate output.
new Listr<Ctx>(
[
{
// Task can also handle and observable
title: 'Observable test.',
task: (): Observable<string> =>
new Observable((observer) => {
observer.next('test')
delay(500)
.then(() => {
observer.next('changed')
return delay(500)
})
.then(() => {
observer.complete()
})
})
}
],
{ concurrent: false }
)
process.stdout
to Render a Stream Directly v2.1.0+
Accessing Since process.stdout
method is controlled by log-update
to create a refreshing interface, for anything else that might need to output data and can use Writeable
streams, task.stdout()
will create a new punch-hole to redirect all the write requests to task.output
. This is especially beneficial for external libraries like enquirer
, which is already integrated, or something like ink
.
This, unfortunately, relies on cleaning all ANSI escape characters, since currently, I do not find a good way to sandbox them inside log-update
which utilizes the cursor position by itself. So use this with caution, because it will only render the last chunk in a stream as well as clean up all the ANSI escape characters except for styles.
This is related to the discussions on issue #31: "How to use it with Ink".
Thanks vinodhum for bringing this up!
import { Box, Color, render } from 'ink'
import React, { Fragment, useEffect, useState } from 'react'
import { Listr } from 'Listr2'
import { Logger } from '@utils/logger'
type Ctx = {}
const logger = new Logger({ useIcons: false })
async function main(): Promise<void> {
let task: Listr<Ctx, 'default'>
task = new Listr<Ctx, 'default'>(
[
{
title: 'This task will show INK as output.',
task: async (ctx, task): Promise<any> => {
const Counter = () => {
const [counter, setCounter] = useState(0)
useEffect(() => {
const timer = setInterval(() => {
setCounter((previousCounter) => previousCounter + 1)
}, 100)
return (): void => {
clearInterval(timer)
}
}, [])
return <Color green>{counter} tests passed</Color>
}
const { unmount, waitUntilExit } = render(<Counter />, task.stdout())
setTimeout(unmount, 2000)
return waitUntilExit()
}
}
],
{ concurrent: false }
)
try {
const context = await task.run()
console.log(`Context: ${JSON.stringify(context)}`)
} catch (e) {
console.error(e)
}
}
main()
Renderer
Default Renderer
Persistent Output
To keep the output after the task has been completed while using the default renderer, you can set { persistentOutput: true }
in the Task
options.
new Listr<Ctx>(
[
{
title: 'This task will execute.',
task: async (ctx, task): Promise<void> => {
task.output = 'I will push an output. [0]'
},
options: { persistentOutput: true }
}
],
{ concurrent: false }
)
Use the Bottom Bar
If task output to the bottom bar is selected, it will create a bar at the end of the tasks leaving one line return space in between.
Items count that is desired to be showed in the bottom bar can be set through Task
option bottomBar
.
- If set to
true
it will only show the last output from the task. - If it is set to a number it will limit the output to that number.
- If set to
Infinity
, it will keep all the output.
new Listr<Ctx>(
[
{
title: 'This task will execute.',
task: async (ctx, task): Promise<void> => {
task.output = 'I will push an output. [0]'
await delay(500)
task.output = 'I will push an output. [1]'
await delay(500)
task.output = 'I will push an output. [2]'
await delay(500)
},
options: {
bottomBar: Infinity
}
}
],
{ concurrent: false }
)