1 | export class ColoredConsole {
|
2 | constructor(targetElement) {
|
3 | this.targetElement = targetElement;
|
4 | this.state = {
|
5 | bold: false,
|
6 | italic: false,
|
7 | underline: false,
|
8 | strikethrough: false,
|
9 | foregroundColor: null,
|
10 | backgroundColor: null,
|
11 | carriageReturn: false,
|
12 | secret: false,
|
13 | };
|
14 | }
|
15 | logs() {
|
16 | return this.targetElement.innerText;
|
17 | }
|
18 | addLine(line) {
|
19 | const re = /(?:\033|\\033)(?:\[(.*?)[@-~]|\].*?(?:\007|\033\\))/g;
|
20 | let i = 0;
|
21 | if (this.state.carriageReturn) {
|
22 | if (line !== "\n") {
|
23 |
|
24 | this.targetElement.removeChild(this.targetElement.lastChild);
|
25 | }
|
26 | this.state.carriageReturn = false;
|
27 | }
|
28 | if (line.includes("\r")) {
|
29 | this.state.carriageReturn = true;
|
30 | }
|
31 | const lineSpan = document.createElement("span");
|
32 | lineSpan.classList.add("line");
|
33 | this.targetElement.appendChild(lineSpan);
|
34 | const addSpan = (content) => {
|
35 | if (content === "")
|
36 | return;
|
37 | const span = document.createElement("span");
|
38 | if (this.state.bold)
|
39 | span.classList.add("log-bold");
|
40 | if (this.state.italic)
|
41 | span.classList.add("log-italic");
|
42 | if (this.state.underline)
|
43 | span.classList.add("log-underline");
|
44 | if (this.state.strikethrough)
|
45 | span.classList.add("log-strikethrough");
|
46 | if (this.state.secret)
|
47 | span.classList.add("log-secret");
|
48 | if (this.state.foregroundColor !== null)
|
49 | span.classList.add(`log-fg-${this.state.foregroundColor}`);
|
50 | if (this.state.backgroundColor !== null)
|
51 | span.classList.add(`log-bg-${this.state.backgroundColor}`);
|
52 | span.appendChild(document.createTextNode(content));
|
53 | lineSpan.appendChild(span);
|
54 | if (this.state.secret) {
|
55 | const redacted = document.createElement("span");
|
56 | redacted.classList.add("log-secret-redacted");
|
57 | redacted.appendChild(document.createTextNode("[redacted]"));
|
58 | lineSpan.appendChild(redacted);
|
59 | }
|
60 | };
|
61 | while (true) {
|
62 | const match = re.exec(line);
|
63 | if (match === null)
|
64 | break;
|
65 | const j = match.index;
|
66 | addSpan(line.substring(i, j));
|
67 | i = j + match[0].length;
|
68 | if (match[1] === undefined)
|
69 | continue;
|
70 | for (const colorCode of match[1].split(";")) {
|
71 | switch (parseInt(colorCode)) {
|
72 | case 0:
|
73 |
|
74 | this.state.bold = false;
|
75 | this.state.italic = false;
|
76 | this.state.underline = false;
|
77 | this.state.strikethrough = false;
|
78 | this.state.foregroundColor = null;
|
79 | this.state.backgroundColor = null;
|
80 | this.state.secret = false;
|
81 | break;
|
82 | case 1:
|
83 | this.state.bold = true;
|
84 | break;
|
85 | case 3:
|
86 | this.state.italic = true;
|
87 | break;
|
88 | case 4:
|
89 | this.state.underline = true;
|
90 | break;
|
91 | case 5:
|
92 | this.state.secret = true;
|
93 | break;
|
94 | case 6:
|
95 | this.state.secret = false;
|
96 | break;
|
97 | case 9:
|
98 | this.state.strikethrough = true;
|
99 | break;
|
100 | case 22:
|
101 | this.state.bold = false;
|
102 | break;
|
103 | case 23:
|
104 | this.state.italic = false;
|
105 | break;
|
106 | case 24:
|
107 | this.state.underline = false;
|
108 | break;
|
109 | case 29:
|
110 | this.state.strikethrough = false;
|
111 | break;
|
112 | case 30:
|
113 | this.state.foregroundColor = "black";
|
114 | break;
|
115 | case 31:
|
116 | this.state.foregroundColor = "red";
|
117 | break;
|
118 | case 32:
|
119 | this.state.foregroundColor = "green";
|
120 | break;
|
121 | case 33:
|
122 | this.state.foregroundColor = "yellow";
|
123 | break;
|
124 | case 34:
|
125 | this.state.foregroundColor = "blue";
|
126 | break;
|
127 | case 35:
|
128 | this.state.foregroundColor = "magenta";
|
129 | break;
|
130 | case 36:
|
131 | this.state.foregroundColor = "cyan";
|
132 | break;
|
133 | case 37:
|
134 | this.state.foregroundColor = "white";
|
135 | break;
|
136 | case 39:
|
137 | this.state.foregroundColor = null;
|
138 | break;
|
139 | case 41:
|
140 | this.state.backgroundColor = "red";
|
141 | break;
|
142 | case 42:
|
143 | this.state.backgroundColor = "green";
|
144 | break;
|
145 | case 43:
|
146 | this.state.backgroundColor = "yellow";
|
147 | break;
|
148 | case 44:
|
149 | this.state.backgroundColor = "blue";
|
150 | break;
|
151 | case 45:
|
152 | this.state.backgroundColor = "magenta";
|
153 | break;
|
154 | case 46:
|
155 | this.state.backgroundColor = "cyan";
|
156 | break;
|
157 | case 47:
|
158 | this.state.backgroundColor = "white";
|
159 | break;
|
160 | case 40:
|
161 | case 49:
|
162 | this.state.backgroundColor = null;
|
163 | break;
|
164 | }
|
165 | }
|
166 | }
|
167 | addSpan(line.substring(i));
|
168 | if (this.targetElement.scrollTop + 56 >=
|
169 | this.targetElement.scrollHeight - this.targetElement.offsetHeight) {
|
170 |
|
171 | this.targetElement.scrollTop = this.targetElement.scrollHeight;
|
172 | }
|
173 | }
|
174 | }
|
175 | export const coloredConsoleStyles = `
|
176 | .log {
|
177 | flex: 1;
|
178 | background-color: #1c1c1c;
|
179 | font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier,
|
180 | monospace;
|
181 | font-size: 12px;
|
182 | padding: 16px;
|
183 | overflow: auto;
|
184 | line-height: 1.45;
|
185 | border-radius: 3px;
|
186 | white-space: pre-wrap;
|
187 | overflow-wrap: break-word;
|
188 | color: #ddd;
|
189 | }
|
190 |
|
191 | .log-bold {
|
192 | font-weight: bold;
|
193 | }
|
194 | .log-italic {
|
195 | font-style: italic;
|
196 | }
|
197 | .log-underline {
|
198 | text-decoration: underline;
|
199 | }
|
200 | .log-strikethrough {
|
201 | text-decoration: line-through;
|
202 | }
|
203 | .log-underline.log-strikethrough {
|
204 | text-decoration: underline line-through;
|
205 | }
|
206 | .log-secret {
|
207 | -webkit-user-select: none;
|
208 | -moz-user-select: none;
|
209 | -ms-user-select: none;
|
210 | user-select: none;
|
211 | }
|
212 | .log-secret-redacted {
|
213 | opacity: 0;
|
214 | width: 1px;
|
215 | font-size: 1px;
|
216 | }
|
217 | .log-fg-black {
|
218 | color: rgb(128, 128, 128);
|
219 | }
|
220 | .log-fg-red {
|
221 | color: rgb(255, 0, 0);
|
222 | }
|
223 | .log-fg-green {
|
224 | color: rgb(0, 255, 0);
|
225 | }
|
226 | .log-fg-yellow {
|
227 | color: rgb(255, 255, 0);
|
228 | }
|
229 | .log-fg-blue {
|
230 | color: rgb(0, 0, 255);
|
231 | }
|
232 | .log-fg-magenta {
|
233 | color: rgb(255, 0, 255);
|
234 | }
|
235 | .log-fg-cyan {
|
236 | color: rgb(0, 255, 255);
|
237 | }
|
238 | .log-fg-white {
|
239 | color: rgb(187, 187, 187);
|
240 | }
|
241 | .log-bg-black {
|
242 | background-color: rgb(0, 0, 0);
|
243 | }
|
244 | .log-bg-red {
|
245 | background-color: rgb(255, 0, 0);
|
246 | }
|
247 | .log-bg-green {
|
248 | background-color: rgb(0, 255, 0);
|
249 | }
|
250 | .log-bg-yellow {
|
251 | background-color: rgb(255, 255, 0);
|
252 | }
|
253 | .log-bg-blue {
|
254 | background-color: rgb(0, 0, 255);
|
255 | }
|
256 | .log-bg-magenta {
|
257 | background-color: rgb(255, 0, 255);
|
258 | }
|
259 | .log-bg-cyan {
|
260 | background-color: rgb(0, 255, 255);
|
261 | }
|
262 | .log-bg-white {
|
263 | background-color: rgb(255, 255, 255);
|
264 | }
|
265 | `;
|