1 | import { round } from '@aryth/math'
|
2 | import { STR } from '@typen/enum-data-types'
|
3 | import { base3ToScale, trailZero } from '../util/humanScale.js'
|
4 |
|
5 | const DEFAULT_SENTENCE = 'progress [{bar}] {progress}% | ETA: {eta}s | {value}/{total}'
|
6 |
|
7 | export class Layout {
|
8 | |
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 | constructor(options) {
|
20 | const char = typeof options.char === STR ? [ options.char, ' ' ] : Array.isArray(options.char) ? options.char : [ '=', '-' ]
|
21 | const [ x, y ] = char
|
22 | this.size = options.size ?? 24
|
23 | this.chars = [ x.repeat(this.size + 1), y.repeat(this.size + 1) ]
|
24 | this.glue = options.glue ?? ''
|
25 | this.autoZero = options.autoZero ?? false
|
26 | this.sentence = options.sentence ?? DEFAULT_SENTENCE
|
27 | if (options.bar) this.bar = options.bar.bind(this)
|
28 | if (options.degree) this.degree = options.degree.bind(this)
|
29 | if (options.format) this.format = options.format.bind(this)
|
30 | }
|
31 |
|
32 | static build(options) {
|
33 | return new Layout(options)
|
34 | }
|
35 |
|
36 | bar(state) {
|
37 | const { progress } = state
|
38 | const { chars, glue, size } = this
|
39 | const
|
40 | lenX = round(progress * size),
|
41 | lenY = size - lenX
|
42 | const [ x, y ] = chars
|
43 |
|
44 | return x.slice(0, lenX) + glue + y.slice(0, lenY)
|
45 | }
|
46 |
|
47 | get fullBar() { return this.chars[0].slice(0, this.size) }
|
48 | get zeroBar() { return this.chars[1].slice(0, this.size) }
|
49 |
|
50 | degree(state) {
|
51 | let { value, total } = state
|
52 | const { base3 = true, decimal = false } = this
|
53 | if (!base3) return `${round(value)}/${total}`
|
54 | const thousand = decimal ? 1000 : 1024
|
55 | let base3Level = 0
|
56 | while (total > thousand) {
|
57 | total /= thousand
|
58 | value /= thousand
|
59 | base3Level++
|
60 | }
|
61 | const t = trailZero(total)
|
62 | const v = trailZero(value).padStart(t.length)
|
63 |
|
64 | return `${v}/${t} ${base3ToScale(base3Level, decimal)}`
|
65 | }
|
66 | |
67 |
|
68 |
|
69 |
|
70 |
|
71 | format(state) {
|
72 | return this.sentence?.replace(/\{(\w+)\}/g, (match, key) => {
|
73 | if (key === 'bar') return this.bar(state)
|
74 | if (key === 'degree') return this.degree(state)
|
75 | if (key in state) return state[key]
|
76 | return match
|
77 | })
|
78 | }
|
79 | } |
\ | No newline at end of file |