1 | import process from 'node:process';
|
2 |
|
3 | const ESC = '\u001B[';
|
4 | const OSC = '\u001B]';
|
5 | const BEL = '\u0007';
|
6 | const SEP = ';';
|
7 |
|
8 |
|
9 | const isBrowser = typeof window !== 'undefined' && typeof window.document !== 'undefined';
|
10 |
|
11 | const isTerminalApp = !isBrowser && process.env.TERM_PROGRAM === 'Apple_Terminal';
|
12 | const isWindows = !isBrowser && process.platform === 'win32';
|
13 | const cwdFunction = isBrowser ? () => {
|
14 | throw new Error('`process.cwd()` only works in Node.js, not the browser.');
|
15 | } : process.cwd;
|
16 |
|
17 | const ansiEscapes = {};
|
18 |
|
19 | ansiEscapes.cursorTo = (x, y) => {
|
20 | if (typeof x !== 'number') {
|
21 | throw new TypeError('The `x` argument is required');
|
22 | }
|
23 |
|
24 | if (typeof y !== 'number') {
|
25 | return ESC + (x + 1) + 'G';
|
26 | }
|
27 |
|
28 | return ESC + (y + 1) + SEP + (x + 1) + 'H';
|
29 | };
|
30 |
|
31 | ansiEscapes.cursorMove = (x, y) => {
|
32 | if (typeof x !== 'number') {
|
33 | throw new TypeError('The `x` argument is required');
|
34 | }
|
35 |
|
36 | let returnValue = '';
|
37 |
|
38 | if (x < 0) {
|
39 | returnValue += ESC + (-x) + 'D';
|
40 | } else if (x > 0) {
|
41 | returnValue += ESC + x + 'C';
|
42 | }
|
43 |
|
44 | if (y < 0) {
|
45 | returnValue += ESC + (-y) + 'A';
|
46 | } else if (y > 0) {
|
47 | returnValue += ESC + y + 'B';
|
48 | }
|
49 |
|
50 | return returnValue;
|
51 | };
|
52 |
|
53 | ansiEscapes.cursorUp = (count = 1) => ESC + count + 'A';
|
54 | ansiEscapes.cursorDown = (count = 1) => ESC + count + 'B';
|
55 | ansiEscapes.cursorForward = (count = 1) => ESC + count + 'C';
|
56 | ansiEscapes.cursorBackward = (count = 1) => ESC + count + 'D';
|
57 |
|
58 | ansiEscapes.cursorLeft = ESC + 'G';
|
59 | ansiEscapes.cursorSavePosition = isTerminalApp ? '\u001B7' : ESC + 's';
|
60 | ansiEscapes.cursorRestorePosition = isTerminalApp ? '\u001B8' : ESC + 'u';
|
61 | ansiEscapes.cursorGetPosition = ESC + '6n';
|
62 | ansiEscapes.cursorNextLine = ESC + 'E';
|
63 | ansiEscapes.cursorPrevLine = ESC + 'F';
|
64 | ansiEscapes.cursorHide = ESC + '?25l';
|
65 | ansiEscapes.cursorShow = ESC + '?25h';
|
66 |
|
67 | ansiEscapes.eraseLines = count => {
|
68 | let clear = '';
|
69 |
|
70 | for (let i = 0; i < count; i++) {
|
71 | clear += ansiEscapes.eraseLine + (i < count - 1 ? ansiEscapes.cursorUp() : '');
|
72 | }
|
73 |
|
74 | if (count) {
|
75 | clear += ansiEscapes.cursorLeft;
|
76 | }
|
77 |
|
78 | return clear;
|
79 | };
|
80 |
|
81 | ansiEscapes.eraseEndLine = ESC + 'K';
|
82 | ansiEscapes.eraseStartLine = ESC + '1K';
|
83 | ansiEscapes.eraseLine = ESC + '2K';
|
84 | ansiEscapes.eraseDown = ESC + 'J';
|
85 | ansiEscapes.eraseUp = ESC + '1J';
|
86 | ansiEscapes.eraseScreen = ESC + '2J';
|
87 | ansiEscapes.scrollUp = ESC + 'S';
|
88 | ansiEscapes.scrollDown = ESC + 'T';
|
89 |
|
90 | ansiEscapes.clearScreen = '\u001Bc';
|
91 |
|
92 | ansiEscapes.clearTerminal = isWindows
|
93 | ? `${ansiEscapes.eraseScreen}${ESC}0f`
|
94 |
|
95 |
|
96 |
|
97 |
|
98 | : `${ansiEscapes.eraseScreen}${ESC}3J${ESC}H`;
|
99 |
|
100 | ansiEscapes.enterAlternativeScreen = ESC + '?1049h';
|
101 | ansiEscapes.exitAlternativeScreen = ESC + '?1049l';
|
102 |
|
103 | ansiEscapes.beep = BEL;
|
104 |
|
105 | ansiEscapes.link = (text, url) => [
|
106 | OSC,
|
107 | '8',
|
108 | SEP,
|
109 | SEP,
|
110 | url,
|
111 | BEL,
|
112 | text,
|
113 | OSC,
|
114 | '8',
|
115 | SEP,
|
116 | SEP,
|
117 | BEL,
|
118 | ].join('');
|
119 |
|
120 | ansiEscapes.image = (buffer, options = {}) => {
|
121 | let returnValue = `${OSC}1337;File=inline=1`;
|
122 |
|
123 | if (options.width) {
|
124 | returnValue += `;width=${options.width}`;
|
125 | }
|
126 |
|
127 | if (options.height) {
|
128 | returnValue += `;height=${options.height}`;
|
129 | }
|
130 |
|
131 | if (options.preserveAspectRatio === false) {
|
132 | returnValue += ';preserveAspectRatio=0';
|
133 | }
|
134 |
|
135 | return returnValue + ':' + buffer.toString('base64') + BEL;
|
136 | };
|
137 |
|
138 | ansiEscapes.iTerm = {
|
139 | setCwd: (cwd = cwdFunction()) => `${OSC}50;CurrentDir=${cwd}${BEL}`,
|
140 |
|
141 | annotation(message, options = {}) {
|
142 | let returnValue = `${OSC}1337;`;
|
143 |
|
144 | const hasX = typeof options.x !== 'undefined';
|
145 | const hasY = typeof options.y !== 'undefined';
|
146 | if ((hasX || hasY) && !(hasX && hasY && typeof options.length !== 'undefined')) {
|
147 | throw new Error('`x`, `y` and `length` must be defined when `x` or `y` is defined');
|
148 | }
|
149 |
|
150 | message = message.replace(/\|/g, '');
|
151 |
|
152 | returnValue += options.isHidden ? 'AddHiddenAnnotation=' : 'AddAnnotation=';
|
153 |
|
154 | if (options.length > 0) {
|
155 | returnValue += (
|
156 | hasX
|
157 | ? [message, options.length, options.x, options.y]
|
158 | : [options.length, message]
|
159 | ).join('|');
|
160 | } else {
|
161 | returnValue += message;
|
162 | }
|
163 |
|
164 | return returnValue + BEL;
|
165 | },
|
166 | };
|
167 |
|
168 | export default ansiEscapes;
|