effective-progress 0.2.4 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -40
- package/package.json +1 -1
- package/src/api.ts +20 -7
- package/src/index.ts +2 -1
- package/src/renderer.ts +1155 -214
- package/src/runtime.ts +106 -32
- package/src/terminal.ts +12 -10
- package/src/theme.ts +87 -0
- package/src/types.ts +12 -11
- package/src/colors.ts +0 -156
package/README.md
CHANGED
|
@@ -11,13 +11,13 @@
|
|
|
11
11
|
|
|
12
12
|
<img alt="Showcase output" src="docs/images/showcase.gif" width="600" />
|
|
13
13
|
|
|
14
|
-
`effective-progress` is an [Effect](https://effect.website/)-first terminal progress library with:
|
|
14
|
+
`effective-progress` is an [Effect](https://effect.website/)-first terminal progress-bar library with:
|
|
15
15
|
|
|
16
|
-
- multiple progress bars
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
-
|
|
16
|
+
- multiple nested tree-like progress bars
|
|
17
|
+
- spinner support for “we have no idea how long this takes” work
|
|
18
|
+
- clean log rendering alongside progress output, so you can keep using `Console.log` / `Effect.logInfo` without wrecking the UI
|
|
19
|
+
- familiar `.all` and `.forEach` APIs — swap `Effect` for `Progress`, get progress bars basically for free
|
|
20
|
+
- flicker-free rendering (in theory) by drawing everything in a single terminal frame
|
|
21
21
|
|
|
22
22
|
## Install
|
|
23
23
|
|
|
@@ -94,6 +94,12 @@ Effect.runPromise(program);
|
|
|
94
94
|
|
|
95
95
|
Configure global renderer behavior once, and a global base progress bar style:
|
|
96
96
|
|
|
97
|
+
Defaults:
|
|
98
|
+
|
|
99
|
+
- determinate layout: `single-line`
|
|
100
|
+
- max task width cap: unset (uses terminal width)
|
|
101
|
+
- bar width: `40`
|
|
102
|
+
|
|
97
103
|
```ts
|
|
98
104
|
import { Effect } from "effect";
|
|
99
105
|
import * as Progress from "effective-progress";
|
|
@@ -105,10 +111,6 @@ const configured = program.pipe(
|
|
|
105
111
|
}),
|
|
106
112
|
Effect.provideService(Progress.ProgressBarConfig, {
|
|
107
113
|
barWidth: 36,
|
|
108
|
-
colors: {
|
|
109
|
-
fill: { kind: "hex", value: "#00b894" },
|
|
110
|
-
spinner: { kind: "ansi256", value: 214 },
|
|
111
|
-
},
|
|
112
114
|
}),
|
|
113
115
|
);
|
|
114
116
|
|
|
@@ -124,9 +126,6 @@ yield *
|
|
|
124
126
|
progressbar: {
|
|
125
127
|
barWidth: 20,
|
|
126
128
|
spinnerFrames: [".", "o", "O", "0"],
|
|
127
|
-
colors: {
|
|
128
|
-
spinner: { kind: "named", value: "magentaBright" },
|
|
129
|
-
},
|
|
130
129
|
},
|
|
131
130
|
});
|
|
132
131
|
```
|
|
@@ -175,40 +174,46 @@ const program = Progress.task(
|
|
|
175
174
|
);
|
|
176
175
|
```
|
|
177
176
|
|
|
178
|
-
##
|
|
177
|
+
## Themes and render stages
|
|
179
178
|
|
|
180
|
-
|
|
179
|
+
Coloring is configured through the `Theme` service.
|
|
181
180
|
|
|
182
181
|
```ts
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
fillChar: "━",
|
|
187
|
-
emptyChar: "─",
|
|
188
|
-
leftBracket: "",
|
|
189
|
-
rightBracket: "",
|
|
190
|
-
colors: {
|
|
191
|
-
fill: { kind: "named", value: "cyan" },
|
|
192
|
-
empty: { kind: "hex", value: "#9ca3af", modifiers: ["dim"] },
|
|
193
|
-
brackets: { kind: "rgb", value: { r: 156, g: 163, b: 175 } },
|
|
194
|
-
percent: { kind: "named", value: "whiteBright", modifiers: ["bold"] },
|
|
195
|
-
spinner: { kind: "ansi256", value: 214 },
|
|
196
|
-
done: { kind: "named", value: "greenBright" },
|
|
197
|
-
failed: { kind: "named", value: "redBright", modifiers: ["bold"] },
|
|
198
|
-
},
|
|
199
|
-
}
|
|
200
|
-
```
|
|
182
|
+
import chalk from "chalk";
|
|
183
|
+
import { Effect } from "effect";
|
|
184
|
+
import * as Progress from "effective-progress";
|
|
201
185
|
|
|
202
|
-
|
|
186
|
+
const program = Progress.task(myEffect, { description: "Work" }).pipe(
|
|
187
|
+
Effect.provideService(
|
|
188
|
+
Progress.Theme,
|
|
189
|
+
Progress.Theme.of({
|
|
190
|
+
styles: {
|
|
191
|
+
plain: (text) => text,
|
|
192
|
+
barFill: chalk.hex("#00b894"),
|
|
193
|
+
barEmpty: chalk.white.dim,
|
|
194
|
+
barBracket: chalk.rgb(180, 190, 210),
|
|
195
|
+
spinner: chalk.ansi256(214),
|
|
196
|
+
statusDone: chalk.greenBright,
|
|
197
|
+
statusFailed: chalk.redBright.bold,
|
|
198
|
+
text: chalk.white,
|
|
199
|
+
units: chalk.whiteBright.bold,
|
|
200
|
+
eta: chalk.gray,
|
|
201
|
+
elapsed: chalk.gray,
|
|
202
|
+
treeConnector: chalk.gray,
|
|
203
|
+
},
|
|
204
|
+
depthPalette: (depth, role) => (role === "text" && depth > 0 ? chalk.cyanBright : undefined),
|
|
205
|
+
}),
|
|
206
|
+
),
|
|
207
|
+
);
|
|
208
|
+
```
|
|
203
209
|
|
|
204
|
-
|
|
205
|
-
- `hex` (for example `#00b894`)
|
|
206
|
-
- `rgb` (for example `{ r: 0, g: 184, b: 148 }`)
|
|
207
|
-
- `ansi256` (for example `214`)
|
|
210
|
+
Render internals are split into overrideable stages:
|
|
208
211
|
|
|
209
|
-
|
|
212
|
+
- `BuildStage`: logical rows/cells/segments
|
|
213
|
+
- `ShrinkStage`: width fitting/collapse
|
|
214
|
+
- `ColorStage`: role -> styled terminal strings
|
|
210
215
|
|
|
211
|
-
|
|
216
|
+
You can replace any stage with `Effect.provideService(...)` while keeping defaults for the rest.
|
|
212
217
|
|
|
213
218
|
## Dependencies & package size
|
|
214
219
|
|
package/package.json
CHANGED
package/src/api.ts
CHANGED
|
@@ -1,11 +1,20 @@
|
|
|
1
|
-
import { Effect, Exit } from "effect";
|
|
1
|
+
import { Effect, Exit, Option } from "effect";
|
|
2
2
|
import { dual } from "effect/Function";
|
|
3
3
|
import type { Concurrency } from "effect/Types";
|
|
4
|
-
import { Progress
|
|
4
|
+
import { Progress } from "./runtime";
|
|
5
5
|
import { Task } from "./types";
|
|
6
6
|
import type { AddTaskOptions, TrackOptions } from "./types";
|
|
7
7
|
import { inferTotal } from "./utils";
|
|
8
8
|
|
|
9
|
+
const provideProgress = <A, E, R>(effect: Effect.Effect<A, E, R>) =>
|
|
10
|
+
Effect.gen(function* () {
|
|
11
|
+
const existing = yield* Effect.serviceOption(Progress);
|
|
12
|
+
if (Option.isSome(existing)) {
|
|
13
|
+
return yield* Effect.provideService(effect, Progress, existing.value);
|
|
14
|
+
}
|
|
15
|
+
return yield* Effect.scoped(effect.pipe(Effect.provide(Progress.Default)));
|
|
16
|
+
});
|
|
17
|
+
|
|
9
18
|
export interface EffectExecutionOptions {
|
|
10
19
|
readonly concurrency?: Concurrency;
|
|
11
20
|
readonly batching?: boolean | "inherit";
|
|
@@ -19,7 +28,9 @@ export interface EffectAllExecutionOptions extends EffectExecutionOptions {
|
|
|
19
28
|
|
|
20
29
|
export type AllOptions = Omit<TrackOptions, "total"> & EffectAllExecutionOptions;
|
|
21
30
|
export type AllReturn<
|
|
22
|
-
Arg extends
|
|
31
|
+
Arg extends
|
|
32
|
+
| ReadonlyArray<Effect.Effect<any, any, any>>
|
|
33
|
+
| Record<string, Effect.Effect<any, any, any>>,
|
|
23
34
|
O extends EffectAllExecutionOptions,
|
|
24
35
|
> = [
|
|
25
36
|
[Arg] extends [ReadonlyArray<Effect.Effect<any, any, any>>]
|
|
@@ -48,7 +59,7 @@ export const task: {
|
|
|
48
59
|
} = dual(
|
|
49
60
|
2,
|
|
50
61
|
<A, E, R>(effect: Effect.Effect<A, E, R>, options: AddTaskOptions) =>
|
|
51
|
-
|
|
62
|
+
provideProgress(
|
|
52
63
|
Effect.gen(function* () {
|
|
53
64
|
const progress = yield* Progress;
|
|
54
65
|
return yield* progress.withTask(effect, options);
|
|
@@ -56,7 +67,9 @@ export const task: {
|
|
|
56
67
|
) as Effect.Effect<A, E, Exclude<R, Progress | Task>>,
|
|
57
68
|
);
|
|
58
69
|
|
|
59
|
-
type AllArg =
|
|
70
|
+
type AllArg =
|
|
71
|
+
| ReadonlyArray<Effect.Effect<any, any, any>>
|
|
72
|
+
| Record<string, Effect.Effect<any, any, any>>;
|
|
60
73
|
|
|
61
74
|
const wrapEffects = (
|
|
62
75
|
effects: AllArg,
|
|
@@ -83,7 +96,7 @@ export const all: {
|
|
|
83
96
|
effects: Arg,
|
|
84
97
|
options: Omit<TrackOptions, "total"> & O,
|
|
85
98
|
) =>
|
|
86
|
-
|
|
99
|
+
provideProgress(
|
|
87
100
|
Effect.gen(function* () {
|
|
88
101
|
const progress = yield* Progress;
|
|
89
102
|
return yield* progress.runTask(
|
|
@@ -143,7 +156,7 @@ export const forEach: {
|
|
|
143
156
|
f: (item: A, index: number) => Effect.Effect<B, E, R>,
|
|
144
157
|
options: ForEachOptions,
|
|
145
158
|
) =>
|
|
146
|
-
|
|
159
|
+
provideProgress(
|
|
147
160
|
Effect.gen(function* () {
|
|
148
161
|
const progress = yield* Progress;
|
|
149
162
|
|