esp32tool 1.6.5 → 1.6.6

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.
@@ -1,3 +1,58 @@
1
+ const ANSI_256: string[] = (() => {
2
+ const t: string[] = [];
3
+ // Standard colors 0-7
4
+ t[0] = "rgb(0,0,0)";
5
+ t[1] = "rgb(128,0,0)";
6
+ t[2] = "rgb(0,128,0)";
7
+ t[3] = "rgb(128,128,0)";
8
+ t[4] = "rgb(0,0,128)";
9
+ t[5] = "rgb(128,0,128)";
10
+ t[6] = "rgb(0,128,128)";
11
+ t[7] = "rgb(192,192,192)";
12
+ // Bright colors 8-15
13
+ t[8] = "rgb(128,128,128)";
14
+ t[9] = "rgb(255,0,0)";
15
+ t[10] = "rgb(0,255,0)";
16
+ t[11] = "rgb(255,255,0)";
17
+ t[12] = "rgb(99,153,255)";
18
+ t[13] = "rgb(255,0,255)";
19
+ t[14] = "rgb(0,255,255)";
20
+ t[15] = "rgb(255,255,255)";
21
+ // 6x6x6 color cube 16-231
22
+ for (let i = 0; i < 216; i++) {
23
+ const r = Math.floor(i / 36);
24
+ const g = Math.floor((i % 36) / 6);
25
+ const b = i % 6;
26
+ t[16 + i] =
27
+ "rgb(" +
28
+ (r ? r * 40 + 55 : 0) +
29
+ "," +
30
+ (g ? g * 40 + 55 : 0) +
31
+ "," +
32
+ (b ? b * 40 + 55 : 0) +
33
+ ")";
34
+ }
35
+ // Grayscale ramp 232-255
36
+ for (let i = 0; i < 24; i++) {
37
+ const v = i * 10 + 8;
38
+ t[232 + i] = "rgb(" + v + "," + v + "," + v + ")";
39
+ }
40
+ return t;
41
+ })();
42
+
43
+ // Maps 256-color indices 0–7 to the named CSS class tokens so that
44
+ // \x1b[38;5;1m renders the same red as \x1b[31m.
45
+ const ANSI_NAMED: (string | null)[] = [
46
+ "black",
47
+ "red",
48
+ "green",
49
+ "yellow",
50
+ "blue",
51
+ "magenta",
52
+ "cyan",
53
+ "white",
54
+ ];
55
+
1
56
  interface ConsoleState {
2
57
  bold: boolean;
3
58
  italic: boolean;
@@ -5,6 +60,10 @@ interface ConsoleState {
5
60
  strikethrough: boolean;
6
61
  foregroundColor: string | null;
7
62
  backgroundColor: string | null;
63
+ fgRgb: string | null;
64
+ bgRgb: string | null;
65
+ dim: boolean;
66
+ reverse: boolean;
8
67
  carriageReturn: boolean;
9
68
  lines: string[];
10
69
  secret: boolean;
@@ -20,6 +79,10 @@ export class ColoredConsole {
20
79
  strikethrough: false,
21
80
  foregroundColor: null,
22
81
  backgroundColor: null,
82
+ fgRgb: null,
83
+ bgRgb: null,
84
+ dim: false,
85
+ reverse: false,
23
86
  carriageReturn: false,
24
87
  lines: [],
25
88
  secret: false,
@@ -39,7 +102,7 @@ export class ColoredConsole {
39
102
  processLine(line: string): Element {
40
103
  // biome-ignore lint/suspicious/noControlCharactersInRegex: ANSI escape sequences
41
104
  // eslint-disable-next-line no-control-regex
42
- const re = /(?:\x1B|\\x1B)(?:\[(.*?)[@-~]|\].*?(?:\x07|\x1B\\))/g;
105
+ const re = /(?:\x1B|\\x1B)(?:\[(.*?)([@-~])|\].*?(?:\x07|\x1B\\))/g;
43
106
  let i = 0;
44
107
 
45
108
  const lineSpan = document.createElement("span");
@@ -50,16 +113,48 @@ export class ColoredConsole {
50
113
 
51
114
  const span = document.createElement("span");
52
115
  if (this.state.bold) span.classList.add("log-bold");
116
+ if (this.state.dim) span.classList.add("log-dim");
53
117
  if (this.state.italic) span.classList.add("log-italic");
54
118
  if (this.state.underline) span.classList.add("log-underline");
55
119
  if (this.state.strikethrough) span.classList.add("log-strikethrough");
56
120
  if (this.state.secret) span.classList.add("log-secret");
57
121
  if (this.state.blink) span.classList.add("log-blink");
58
122
  if (this.state.rapidBlink) span.classList.add("log-rapid-blink");
59
- if (this.state.foregroundColor !== null)
60
- span.classList.add(`log-fg-${this.state.foregroundColor}`);
61
- if (this.state.backgroundColor !== null)
62
- span.classList.add(`log-bg-${this.state.backgroundColor}`);
123
+
124
+ // Resolve colors with reverse-video support
125
+ let fgRgb = this.state.fgRgb;
126
+ let bgRgb = this.state.bgRgb;
127
+ let fg = this.state.foregroundColor;
128
+ let bg = this.state.backgroundColor;
129
+
130
+ if (this.state.reverse) {
131
+ fgRgb = this.state.bgRgb;
132
+ bgRgb = this.state.fgRgb;
133
+ fg = this.state.backgroundColor;
134
+ bg = this.state.foregroundColor;
135
+ // When one side is unset, fill in the terminal defaults so the
136
+ // swap is always visible (fg default=#ddd, bg default=#1c1c1c).
137
+ if (!fgRgb && !fg && !bgRgb && !bg) {
138
+ span.classList.add("log-reverse");
139
+ } else {
140
+ if (!fgRgb && !fg) fgRgb = "rgb(28,28,28)";
141
+ if (!bgRgb && !bg) bgRgb = "rgb(221,221,221)";
142
+ }
143
+ }
144
+
145
+ // Inline rgb() style takes priority over CSS class
146
+ if (fgRgb) {
147
+ span.style.color = fgRgb;
148
+ } else if (fg !== null) {
149
+ span.classList.add(`log-fg-${fg}`);
150
+ }
151
+
152
+ if (bgRgb) {
153
+ span.style.backgroundColor = bgRgb;
154
+ } else if (bg !== null) {
155
+ span.classList.add(`log-bg-${bg}`);
156
+ }
157
+
63
158
  span.appendChild(document.createTextNode(content));
64
159
  lineSpan.appendChild(span);
65
160
 
@@ -79,18 +174,39 @@ export class ColoredConsole {
79
174
  addSpan(line.substring(i, j));
80
175
  i = j + match[0].length;
81
176
 
82
- if (match[1] === undefined) continue;
177
+ // Only process SGR sequences (final byte 'm'); skip cursor, erase, etc.
178
+ if (match[1] === undefined || match[2] !== "m") continue;
83
179
 
84
- for (const colorCode of match[1].split(";")) {
85
- switch (parseInt(colorCode)) {
180
+ const rawCodes = match[1] === "" ? [""] : match[1].split(";");
181
+ const codes = [];
182
+ let invalidSgr = false;
183
+ for (const rawCode of rawCodes) {
184
+ if (rawCode === "") {
185
+ codes.push(0);
186
+ continue;
187
+ }
188
+ if (!/^\d+$/.test(rawCode)) {
189
+ invalidSgr = true;
190
+ break;
191
+ }
192
+ codes.push(Number(rawCode));
193
+ }
194
+ if (invalidSgr) continue;
195
+
196
+ for (let ci = 0; ci < codes.length; ci++) {
197
+ const code = codes[ci];
198
+ switch (code) {
86
199
  case 0:
87
- // reset
88
200
  this.state.bold = false;
201
+ this.state.dim = false;
89
202
  this.state.italic = false;
90
203
  this.state.underline = false;
91
204
  this.state.strikethrough = false;
92
205
  this.state.foregroundColor = null;
93
206
  this.state.backgroundColor = null;
207
+ this.state.fgRgb = null;
208
+ this.state.bgRgb = null;
209
+ this.state.reverse = false;
94
210
  this.state.secret = false;
95
211
  this.state.blink = false;
96
212
  this.state.rapidBlink = false;
@@ -98,6 +214,9 @@ export class ColoredConsole {
98
214
  case 1:
99
215
  this.state.bold = true;
100
216
  break;
217
+ case 2:
218
+ this.state.dim = true;
219
+ break;
101
220
  case 3:
102
221
  this.state.italic = true;
103
222
  break;
@@ -112,6 +231,9 @@ export class ColoredConsole {
112
231
  this.state.rapidBlink = true;
113
232
  this.state.blink = false;
114
233
  break;
234
+ case 7:
235
+ this.state.reverse = true;
236
+ break;
115
237
  case 8:
116
238
  this.state.secret = true;
117
239
  break;
@@ -120,6 +242,7 @@ export class ColoredConsole {
120
242
  break;
121
243
  case 22:
122
244
  this.state.bold = false;
245
+ this.state.dim = false;
123
246
  break;
124
247
  case 23:
125
248
  this.state.italic = false;
@@ -131,6 +254,9 @@ export class ColoredConsole {
131
254
  this.state.blink = false;
132
255
  this.state.rapidBlink = false;
133
256
  break;
257
+ case 27:
258
+ this.state.reverse = false;
259
+ break;
134
260
  case 28:
135
261
  this.state.secret = false;
136
262
  break;
@@ -139,57 +265,203 @@ export class ColoredConsole {
139
265
  break;
140
266
  case 30:
141
267
  this.state.foregroundColor = "black";
268
+ this.state.fgRgb = null;
142
269
  break;
143
270
  case 31:
144
271
  this.state.foregroundColor = "red";
272
+ this.state.fgRgb = null;
145
273
  break;
146
274
  case 32:
147
275
  this.state.foregroundColor = "green";
276
+ this.state.fgRgb = null;
148
277
  break;
149
278
  case 33:
150
279
  this.state.foregroundColor = "yellow";
280
+ this.state.fgRgb = null;
151
281
  break;
152
282
  case 34:
153
283
  this.state.foregroundColor = "blue";
284
+ this.state.fgRgb = null;
154
285
  break;
155
286
  case 35:
156
287
  this.state.foregroundColor = "magenta";
288
+ this.state.fgRgb = null;
157
289
  break;
158
290
  case 36:
159
291
  this.state.foregroundColor = "cyan";
292
+ this.state.fgRgb = null;
160
293
  break;
161
294
  case 37:
162
295
  this.state.foregroundColor = "white";
296
+ this.state.fgRgb = null;
297
+ break;
298
+ case 38:
299
+ // Extended foreground: 38;5;n (256-color) or 38;2;r;g;b (true-color)
300
+ if (ci + 1 < codes.length) {
301
+ if (codes[ci + 1] === 5) {
302
+ if (ci + 2 < codes.length) {
303
+ const idx = codes[ci + 2];
304
+ if (idx >= 0 && idx <= 7 && ANSI_NAMED[idx]) {
305
+ this.state.foregroundColor = ANSI_NAMED[idx];
306
+ this.state.fgRgb = null;
307
+ } else if (idx >= 0 && idx <= 255 && ANSI_256[idx]) {
308
+ this.state.foregroundColor = null;
309
+ this.state.fgRgb = ANSI_256[idx];
310
+ }
311
+ ci += 2;
312
+ } else {
313
+ ci += 1;
314
+ }
315
+ } else if (codes[ci + 1] === 2) {
316
+ if (ci + 4 < codes.length) {
317
+ this.state.foregroundColor = null;
318
+ const r = Math.max(0, Math.min(255, codes[ci + 2]));
319
+ const g = Math.max(0, Math.min(255, codes[ci + 3]));
320
+ const b = Math.max(0, Math.min(255, codes[ci + 4]));
321
+ this.state.fgRgb = "rgb(" + r + "," + g + "," + b + ")";
322
+ ci += 4;
323
+ } else {
324
+ ci = codes.length - 1;
325
+ }
326
+ }
327
+ }
163
328
  break;
164
329
  case 39:
165
330
  this.state.foregroundColor = null;
331
+ this.state.fgRgb = null;
166
332
  break;
167
333
  case 40:
168
334
  this.state.backgroundColor = "black";
335
+ this.state.bgRgb = null;
169
336
  break;
170
337
  case 41:
171
338
  this.state.backgroundColor = "red";
339
+ this.state.bgRgb = null;
172
340
  break;
173
341
  case 42:
174
342
  this.state.backgroundColor = "green";
343
+ this.state.bgRgb = null;
175
344
  break;
176
345
  case 43:
177
346
  this.state.backgroundColor = "yellow";
347
+ this.state.bgRgb = null;
178
348
  break;
179
349
  case 44:
180
350
  this.state.backgroundColor = "blue";
351
+ this.state.bgRgb = null;
181
352
  break;
182
353
  case 45:
183
354
  this.state.backgroundColor = "magenta";
355
+ this.state.bgRgb = null;
184
356
  break;
185
357
  case 46:
186
358
  this.state.backgroundColor = "cyan";
359
+ this.state.bgRgb = null;
187
360
  break;
188
361
  case 47:
189
362
  this.state.backgroundColor = "white";
363
+ this.state.bgRgb = null;
364
+ break;
365
+ case 48:
366
+ // Extended background: 48;5;n (256-color) or 48;2;r;g;b (true-color)
367
+ if (ci + 1 < codes.length) {
368
+ if (codes[ci + 1] === 5) {
369
+ if (ci + 2 < codes.length) {
370
+ const idx = codes[ci + 2];
371
+ if (idx >= 0 && idx <= 7 && ANSI_NAMED[idx]) {
372
+ this.state.backgroundColor = ANSI_NAMED[idx];
373
+ this.state.bgRgb = null;
374
+ } else if (idx >= 0 && idx <= 255 && ANSI_256[idx]) {
375
+ this.state.backgroundColor = null;
376
+ this.state.bgRgb = ANSI_256[idx];
377
+ }
378
+ ci += 2;
379
+ } else {
380
+ ci += 1;
381
+ }
382
+ } else if (codes[ci + 1] === 2) {
383
+ if (ci + 4 < codes.length) {
384
+ this.state.backgroundColor = null;
385
+ const r = Math.max(0, Math.min(255, codes[ci + 2]));
386
+ const g = Math.max(0, Math.min(255, codes[ci + 3]));
387
+ const b = Math.max(0, Math.min(255, codes[ci + 4]));
388
+ this.state.bgRgb = "rgb(" + r + "," + g + "," + b + ")";
389
+ ci += 4;
390
+ } else {
391
+ ci = codes.length - 1;
392
+ }
393
+ }
394
+ }
190
395
  break;
191
396
  case 49:
192
397
  this.state.backgroundColor = null;
398
+ this.state.bgRgb = null;
399
+ break;
400
+ // Bright foreground colors
401
+ case 90:
402
+ this.state.foregroundColor = null;
403
+ this.state.fgRgb = ANSI_256[8];
404
+ break;
405
+ case 91:
406
+ this.state.foregroundColor = null;
407
+ this.state.fgRgb = ANSI_256[9];
408
+ break;
409
+ case 92:
410
+ this.state.foregroundColor = null;
411
+ this.state.fgRgb = ANSI_256[10];
412
+ break;
413
+ case 93:
414
+ this.state.foregroundColor = null;
415
+ this.state.fgRgb = ANSI_256[11];
416
+ break;
417
+ case 94:
418
+ this.state.foregroundColor = null;
419
+ this.state.fgRgb = ANSI_256[12];
420
+ break;
421
+ case 95:
422
+ this.state.foregroundColor = null;
423
+ this.state.fgRgb = ANSI_256[13];
424
+ break;
425
+ case 96:
426
+ this.state.foregroundColor = null;
427
+ this.state.fgRgb = ANSI_256[14];
428
+ break;
429
+ case 97:
430
+ this.state.foregroundColor = null;
431
+ this.state.fgRgb = ANSI_256[15];
432
+ break;
433
+ // Bright background colors
434
+ case 100:
435
+ this.state.backgroundColor = null;
436
+ this.state.bgRgb = ANSI_256[8];
437
+ break;
438
+ case 101:
439
+ this.state.backgroundColor = null;
440
+ this.state.bgRgb = ANSI_256[9];
441
+ break;
442
+ case 102:
443
+ this.state.backgroundColor = null;
444
+ this.state.bgRgb = ANSI_256[10];
445
+ break;
446
+ case 103:
447
+ this.state.backgroundColor = null;
448
+ this.state.bgRgb = ANSI_256[11];
449
+ break;
450
+ case 104:
451
+ this.state.backgroundColor = null;
452
+ this.state.bgRgb = ANSI_256[12];
453
+ break;
454
+ case 105:
455
+ this.state.backgroundColor = null;
456
+ this.state.bgRgb = ANSI_256[13];
457
+ break;
458
+ case 106:
459
+ this.state.backgroundColor = null;
460
+ this.state.bgRgb = ANSI_256[14];
461
+ break;
462
+ case 107:
463
+ this.state.backgroundColor = null;
464
+ this.state.bgRgb = ANSI_256[15];
193
465
  break;
194
466
  }
195
467
  }
@@ -210,8 +482,6 @@ export class ColoredConsole {
210
482
  }
211
483
 
212
484
  for (const line of this.state.lines) {
213
- // A lone \r is a pure carriage-return signal — update state but don't
214
- // create a DOM node for it (it has no renderable content).
215
485
  if (line === "\r") {
216
486
  this.state.carriageReturn = true;
217
487
  continue;
@@ -238,14 +508,12 @@ export class ColoredConsole {
238
508
 
239
509
  this.state.lines = [];
240
510
 
241
- // Keep scroll at bottom
242
511
  if (atBottom) {
243
512
  this.targetElement.scrollTop = this.targetElement.scrollHeight;
244
513
  }
245
514
  }
246
515
 
247
516
  addLine(line: string) {
248
- // Processing of lines is deferred for performance reasons
249
517
  if (this.state.lines.length === 0) {
250
518
  setTimeout(() => this.processLines(), 0);
251
519
  }
@@ -272,6 +540,9 @@ export const coloredConsoleStyles = `
272
540
  .log-bold {
273
541
  font-weight: bold;
274
542
  }
543
+ .log-dim {
544
+ opacity: 0.5;
545
+ }
275
546
  .log-italic {
276
547
  font-style: italic;
277
548
  }
@@ -306,6 +577,10 @@ export const coloredConsoleStyles = `
306
577
  width: 1px;
307
578
  font-size: 1px;
308
579
  }
580
+ .log-reverse {
581
+ background: #ddd;
582
+ color: #1c1c1c;
583
+ }
309
584
  .log-fg-black {
310
585
  color: rgb(128, 128, 128);
311
586
  }
@@ -1,15 +1,13 @@
1
- // Matches lines that already carry a wall-clock or tick timestamp so we don't
2
- // add a redundant one. Intentionally does NOT match bare log-level prefixes
3
- // like ESPHome's [I][tag:line]: those have no time information.
4
- //
1
+ // Matches lines that already carry a wall-clock timestamp so we don't add a
2
+ // redundant one. Only real wall-clock formats are matched — tick-based
3
+ // formats like FreeRTOS "(12345)" or ESP-IDF "I (15) boot:" are NOT matched
4
+ // because they don't carry time-of-day information
5
5
  // Covered formats:
6
- // (123456) FreeRTOS ms-tick e.g. "(12345) "
7
6
  // [HH:MM:SS] wall-clock bracket
8
7
  // [HH:MM:SS.mmm] wall-clock bracket with millis
9
- // I (1234) tag: ESP-IDF log level + tick e.g. "I (1234) wifi: ..."
10
8
  // HH:MM:SS.mmm plain wall-clock
11
9
  const DEVICE_TIMESTAMP_RE =
12
- /^\s*(?:\(\d+\)\s|\[\d{2}:\d{2}:\d{2}(?:\.\d+)?\]|[DIWEACV] \(\d+\) \w|(?:\d{2}:){2}\d{2}\.\d)/;
10
+ /^\s*(?:\[\d{2}:\d{2}:\d{2}(?:\.\d+)?\]|(?:\d{2}:){2}\d{2}\.\d)/;
13
11
 
14
12
  export class TimestampTransformer implements Transformer<string, string> {
15
13
  private deviceHasTimestamps = false;
package/sw.js CHANGED
@@ -1,5 +1,5 @@
1
1
  // Service Worker for ESP32Tool PWA
2
- const CACHE_NAME = 'esp32tool-v1.6.5';
2
+ const CACHE_NAME = 'esp32tool-v1.6.6';
3
3
  const RUNTIME_CACHE = 'esp32tool-runtime';
4
4
 
5
5
  // Core files to cache on install (relative paths work for any deployment path)