-
-
Notifications
You must be signed in to change notification settings - Fork 64
/
ansi.ts
110 lines (96 loc) 路 2.49 KB
/
ansi.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
import * as ansiEscapes from "./ansi_escapes.ts";
import type { Chain } from "./chain.ts";
type Args = Array<unknown>;
type Executor = (this: AnsiChain, ...args: Args) => string;
type Property = string | Executor;
type PropertyNames = keyof Chain<AnsiChain>;
/** Ansi instance returned by all ansi escape properties. */
export interface AnsiChain extends Chain<AnsiChain> {
/** Get ansi escape sequence. */
(): string;
/** Get ansi escape sequence. */
toString(): string;
/** Get ansi escape sequence as Uint8Array. */
toBuffer(): Uint8Array;
}
/** Create new `Ansi` instance. */
export type AnsiFactory = () => Ansi;
/**
* Chainable ansi escape sequences.
* If invoked as method, a new Ansi instance will be returned.
*/
export type Ansi = AnsiFactory & AnsiChain;
/**
* Chainable ansi escape sequences.
* If invoked as method, a new Ansi instance will be returned.
* ```
* await Deno.stdout.write(
* new TextEncoder().encode(
* ansi.cursorTo(0, 0).eraseScreen(),
* ),
* );
* ```
* Or shorter:
* ```
* await Deno.stdout.write(
* ansi.cursorTo(0, 0).eraseScreen.toBuffer(),
* );
* ```
*/
export const ansi: Ansi = factory();
function factory(): Ansi {
let result: Array<string> = [];
let stack: Array<[Property, Args]> = [];
const ansi: Ansi = function (
this: AnsiChain | undefined,
...args: Args
): string | AnsiChain {
if (this) {
if (args.length) {
update(args);
return this;
}
return this.toString();
}
return factory();
} as Ansi;
ansi.text = function (text: string): AnsiChain {
stack.push([text, []]);
return this;
};
ansi.toString = function (): string {
update();
const str: string = result.join("");
result = [];
return str;
};
ansi.toBuffer = function (): Uint8Array {
return new TextEncoder().encode(this.toString());
};
const methodList: Array<[PropertyNames, Property]> = Object.entries(
ansiEscapes,
) as Array<[PropertyNames, Property]>;
for (const [name, method] of methodList) {
Object.defineProperty(ansi, name, {
get(this: AnsiChain) {
stack.push([method, []]);
return this;
},
});
}
return ansi;
function update(args?: Args) {
if (!stack.length) {
return;
}
if (args) {
stack[stack.length - 1][1] = args;
}
result.push(
...stack.map(([prop, args]: [Property, Args]) =>
typeof prop === "string" ? prop : prop.call(ansi, ...args)
),
);
stack = [];
}
}