Skip to content

Output

Task can push output while running for informing the user of what is going on or programmatically for more information about an underlying task.

Example

You can find the related examples here.

Usage

Depending on the renderer selected, the format of the output will change. For DefaultRenderer everything will be rendered in a small bar just after the task, while for SimpleRenderer, VerboseRenderer, or TestRenderer it will be more like a logger. You can find the individual properties for Task output behavior in the next section.

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.

ts
import { delay, Listr } from 'listr2'

const tasks = new Listr(
  [
    {
      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 }
)

await tasks.run()

Passing Data Through an Observable or a Stream

Since observables and streams are supported they can also be used to generate output.

Code Example — Stream
ts
import { spawn } from 'child_process'
import type { Readable } from 'stream'

import { Listr } from 'listr2'

const tasks = new Listr(
  [
    {
      title: 'This task will execute.',
      task: async (): Promise<Readable> => {
        return spawn('ls').stdout
      },
      rendererOptions: {
        persistentOutput: true
      }
    }
  ],
  { concurrent: false }
)

await tasks.run()
Code Example — Observable
ts
import { Observable } from 'rxjs'

import { delay, Listr } from 'listr2'

const tasks = new Listr(
  [
    {
      // Task can also handle and observable
      title: 'Observable test.',
      task: (): Observable<string> =>
        new Observable((observer) => {
          observer.next('test')

          void delay(500)
            .then(() => {
              observer.next('changed')

              return delay(500)
            })
            .then(() => {
              observer.complete()
            })
        })
    }
  ],
  { concurrent: false }
)

await tasks.run()

Render a WritableStream Directly

v2.1.0 #31

process.stdout and process.stderr might get hooked depending on the usage of ProcessOutput on the selected renderer. So anything that requires a WritableStream while the task running to dump the output, should go through the Listr itself by creating a temporary WritableStream with task.stdout().

Render Output of a Command

v6.5.0 #677

Task output can be piped to the task.stdout() directly since it is a WritableStream, whenever you are running something that writes to the process.output. This usually can be utilized to show the outputs of the commands.

Code Example
ts
import { execaCommand as command } from 'execa'

import { Listr } from 'listr2'

const tasks = new Listr([
  {
    title: 'This task will do a curl request.',
    task: async (_, task): Promise<void> => {
      const execute = command('curl -v http://google.com')

      execute.stdout.pipe(task.stdout())
      execute.stderr.pipe(task.stdout())

      await execute
    },
    rendererOptions: {
      outputBar: Infinity,
      persistentOutput: true
    }
  }
])

await tasks.run()

Whenever more control over the stream is required, temporary WritableStream can be created through helper function createWritable via passing it a callback to dictate the behavior of the write call.

Code Example
ts
import { execaCommand as command } from 'execa'

import { Listr, createWritable } from 'listr2'

const tasks = new Listr([
  {
    title: 'This task will list the directory.',
    task: async (_, task): Promise<void> => {
      const output = createWritable((chunk: string) => {
        if (chunk.toString().match(/.*Connected to.*/)) {
          task.output = 'Connection successful.'
        }
      })

      const execute = command('curl -v http://google.com')

      execute.stdout.pipe(output)
      execute.stderr.pipe(output)

      await execute
    },
    rendererOptions: {
      persistentOutput: true
    }
  }
])

await tasks.run()

Renderer

DefaultRenderer

Use the Output Bar v7.0.0 #686

For DefaultRenderer, if the task has a title, last line of output will be rendered under the task title by default.

Item count that is desired to be showed in the output bar can be set through the renderer option outputBar and is per-task.

  • true only keep the last line.
  • Infinity will keep all the lines.
  • number will keep the defined amount of lines.
  • false will not render output with this method.
Code Example
ts
import { delay, Listr } from 'listr2'

const tasks = new Listr(
  [
    {
      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)
      },
      rendererOptions: {
        outputBar: Infinity
      }
    }
  ],
  { concurrent: false }
)

await tasks.run()

Use the Bottom Bar

For DefaultRenderer, data can be outputted to a bar below all the render area, this is useful for fast moving logs. If the task has no title, last line of output will be rendered in the bottom bar by default.

Bottom bar can be selected through Task renderer options, where it will create a bar at the end of the tasks leaving one line return space in between.

Item count that is desired to be showed in the bottom bar can be set through the renderer option bottomBar and is per-task.

  • true only keep the last line.
  • Infinity will keep all the lines.
  • number will keep the defined amount of lines.
  • false will not render output with this method.
Code Example
ts
import { delay, Listr } from 'listr2'

const tasks = new Listr(
  [
    {
      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)
      },
      rendererOptions: {
        bottomBar: Infinity
      }
    }
  ],
  { concurrent: false }
)

await tasks.run()

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 or Listr renderer options.

Code Example
ts
import { delay, Listr } from 'listr2'

const tasks = new Listr(
  [
    {
      title: 'This task will execute.',
      task: async (ctx, task): Promise<void> => {
        task.output = 'I will push an output. [0]'
      },
      rendererOptions: { persistentOutput: true }
    }
  ],
  { concurrent: false }
)

await tasks.run()