Subtasks
listr2
can be infinitely nested by utilizing subtasks, which is the core part of the design.
A Task can return a new Listr. But rather than calling it by invoking a new Listr
to get the full auto-completion features depending on the parent task's selected renderer, it is mandatory to call it through the Task itself by task.newListr()
since they are sharing components internally that makes the application tick.
Subtasks can be nested indefinitely as long as the terminal width is enough to support them.
Subtasks give the advantage of grouping similar tasks, changing the behavior of Listr for a certain set of tasks, or cleaning up the rendering area when certain tasks have finished.
Usage
import { delay, Listr } from 'listr2'
const tasks = new Listr(
[
{
title: 'This task will execute.',
task: (ctx, task): Listr =>
task.newListr([
{
title: 'This is a subtask.',
task: async (): Promise<void> => {
await delay(3000)
}
}
])
}
],
{ concurrent: false }
)
await tasks.run()
Example
You can find the related examples here.
Overwriting the Default Behavior Through Subtask Options
You can change the behavior of Listr, and the selected renderer of the parent through the options of a subtask.
This includes selected renderer options as well as Listr options like exitOnError
, concurrent
to be set per-subtaskly independent of the parent task, while it will always inherit the defaults from the parent task.
Due to design limitations of making renderers a bit simpler, some of the options that cannot be changed from the renderer are marked as @global
in the hover documentation. This is not disabled through typings due to keeping the renderer instances fully self-contained.
Code Example
import { delay, Listr } from 'listr2'
const tasks = new Listr(
[
{
title: 'This task will execute.',
task: (ctx, task): Listr =>
task.newListr(
[
{
title: 'This is a subtask.',
task: async (): Promise<void> => {
await delay(3000)
}
},
{
title: 'This is an another subtask.',
task: async (): Promise<void> => {
await delay(2000)
}
}
],
{ concurrent: true, rendererOptions: { collapseSubtasks: true } }
)
},
{
title: 'This task will execute.',
task: (ctx, task): Listr =>
task.newListr(
[
{
title: 'This is a subtask.',
task: async (): Promise<void> => {
await delay(3000)
}
},
{
title: 'This is an another subtask.',
task: async (): Promise<void> => {
await delay(2000)
}
}
],
{ concurrent: false, rendererOptions: { collapseSubtasks: false } }
)
}
],
{ concurrent: false }
)
const ctx = await tasks.run()
Access Parent Task from Subtasks
v2.6.0 #141You can access the parent task class from subtasks by passing the function signature (parent) => Listr
to task.newListr
. This way you can change the title of the parent task or access its functionality.
Code Example
import { delay, Listr } from 'listr2'
const tasks = new Listr(
[
{
title: 'This task will execute.',
task: (ctx, task): Listr =>
task.newListr(
(parent) => [
{
title: 'This is a subtask.',
task: async (): Promise<void> => {
await delay(3000)
parent.title = 'I am changing the title from subtask.'
}
}
],
{ concurrent: true }
)
}
],
{ concurrent: false }
)
const ctx = await tasks.run()