Skip to content

Commit 3aedede

Browse files
authored
Merge pull request #59 from tim-stasse/ansi-up
Update ansi_up
2 parents 9099f62 + ec01202 commit 3aedede

File tree

2 files changed

+118
-33
lines changed

2 files changed

+118
-33
lines changed

packages/module/src/LogViewer/LogViewer.tsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ interface LogViewerProps {
5757
}) => void;
5858
/** Forwarded ref */
5959
innerRef?: React.RefObject<any>;
60+
/** Flag to enable or disable the use of classes (instead of inline styles) for ANSI coloring/formatting. */
61+
useAnsiClasses?: boolean;
6062
}
6163

6264
let canvas: HTMLCanvasElement | undefined;
@@ -89,6 +91,7 @@ const LogViewerBase: React.FunctionComponent<LogViewerProps> = memo(
8991
innerRef,
9092
isTextWrapped = true,
9193
initialIndexWidth,
94+
useAnsiClasses,
9295
...props
9396
}: LogViewerProps) => {
9497
const [searchedInput, setSearchedInput] = useState<string | null>('');
@@ -106,6 +109,10 @@ const LogViewerBase: React.FunctionComponent<LogViewerProps> = memo(
106109
const parsedData = React.useMemo(() => parseConsoleOutput(data), [data]);
107110

108111
const ansiUp = new AnsiUp();
112+
// eslint-disable-next-line camelcase
113+
ansiUp.escape_html = false;
114+
// eslint-disable-next-line camelcase
115+
ansiUp.use_classes = useAnsiClasses;
109116

110117
const ref = React.useRef<any>();
111118
const logViewerRef = innerRef || ref;

packages/module/src/ansi_up/ansi_up.ts

Lines changed: 111 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ interface TextWithAttr {
2020
fg: AU_Color;
2121
bg: AU_Color;
2222
bold: boolean;
23+
faint: boolean;
2324
italic: boolean;
2425
underline: boolean;
2526
text: string;
@@ -48,7 +49,7 @@ interface TextPacket {
4849
//
4950

5051
export default class AnsiUp {
51-
VERSION = '5.0.1';
52+
VERSION = '6.0.2';
5253

5354
//
5455
// *** SEE README ON GITHUB FOR PUBLIC API ***
@@ -62,6 +63,7 @@ export default class AnsiUp {
6263
private fg: AU_Color;
6364
private bg: AU_Color;
6465
private bold: boolean;
66+
private faint: boolean;
6567
private italic: boolean;
6668
private underline: boolean;
6769
private _use_classes: boolean;
@@ -71,14 +73,22 @@ export default class AnsiUp {
7173
private _osc_st: RegExp;
7274
private _osc_regex: RegExp;
7375

74-
private _url_whitelist: any = {};
76+
private _url_allowlist: Record<string, boolean | number> = {};
77+
private _escape_html: boolean;
7578

7679
private _buffer: string;
7780

81+
private _boldStyle: string;
82+
private _faintStyle: string;
83+
private _italicStyle: string;
84+
private _underlineStyle: string;
85+
7886
constructor() {
7987
// All construction occurs here
8088
this.setup_palettes();
8189
this.resetStyles();
90+
91+
this._use_classes = false;
8292
}
8393

8494
set use_classes(arg: boolean) {
@@ -89,14 +99,33 @@ export default class AnsiUp {
8999
return this._use_classes;
90100
}
91101

92-
set url_whitelist(arg: {}) {
93-
this._url_whitelist = arg;
102+
set url_allowlist(arg: Record<string, boolean | number>) {
103+
this._url_allowlist = arg;
94104
}
95105

96-
get url_whitelist(): {} {
97-
return this._url_whitelist;
106+
get url_allowlist(): Record<string, boolean | number> {
107+
return this._url_allowlist;
98108
}
99109

110+
set escape_html(arg: boolean)
111+
{
112+
this._escape_html = arg;
113+
}
114+
115+
get escape_html(): boolean
116+
{
117+
return this._escape_html;
118+
}
119+
120+
set boldStyle(arg: string) { this._boldStyle = arg; }
121+
get boldStyle(): string { return this._boldStyle; }
122+
set faintStyle(arg: string) { this._faintStyle = arg; }
123+
get faintStyle(): string { return this._faintStyle; }
124+
set italicStyle(arg: string) { this._italicStyle = arg; }
125+
get italicStyle(): string { return this._italicStyle; }
126+
set underlineStyle(arg: string) { this._underlineStyle = arg; }
127+
get underlineStyle(): string { return this._underlineStyle; }
128+
100129
private setup_palettes(): void {
101130
this.ansi_colors = [
102131
// Normal colors
@@ -154,6 +183,10 @@ export default class AnsiUp {
154183
}
155184

156185
private escape_txt_for_html(txt: string): string {
186+
if (!this._escape_html) {
187+
return txt;
188+
}
189+
157190
return txt.replace(/[&<>"']/gm, str => {
158191
if (str === '&') {
159192
return '&amp;';
@@ -209,7 +242,9 @@ export default class AnsiUp {
209242

210243
// NOW WE HANDLE ESCAPES
211244
if (pos == 0) {
212-
if (len == 1) {
245+
// All of the sequences typically need at least 3 characters
246+
// So, wait until we have at least that many
247+
if (len < 3) {
213248
// Lone ESC in Buffer, We don't know yet
214249
pkt.kind = PacketKind.Incomplete;
215250
return pkt;
@@ -218,9 +253,8 @@ export default class AnsiUp {
218253
const next_char = this._buffer.charAt(1);
219254

220255
// We treat this as a single ESC
221-
// Which effecitvely shows
222-
if (next_char != '[' && next_char != ']') {
223-
// DeMorgan
256+
// No transformation
257+
if (next_char != '[' && next_char != ']' && (next_char != '(')) {
224258
pkt.kind = PacketKind.ESC;
225259
pkt.text = this._buffer.slice(0, 1);
226260
this._buffer = this._buffer.slice(1);
@@ -311,10 +345,8 @@ export default class AnsiUp {
311345
var rpos = match[0].length;
312346
this._buffer = this._buffer.slice(rpos);
313347
return pkt;
314-
}
315-
316-
// OSC CHECK
317-
if (next_char == ']') {
348+
} else if (next_char == ']') {
349+
// OSC CHECK
318350
if (len < 4) {
319351
pkt.kind = PacketKind.Incomplete;
320352
return pkt;
@@ -470,6 +502,15 @@ export default class AnsiUp {
470502
var rpos = match[0].length;
471503
this._buffer = this._buffer.slice(rpos);
472504
return pkt;
505+
} else if (next_char == '(') {
506+
// Other ESC CHECK
507+
// This specifies the character set, which
508+
// should just be ignored
509+
510+
// We have at least 3, so drop the sequence
511+
pkt.kind = PacketKind.Unknown;
512+
this._buffer = this._buffer.slice(3);
513+
return pkt;
473514
}
474515
}
475516
}
@@ -504,21 +545,26 @@ export default class AnsiUp {
504545
}
505546

506547
resetStyles() {
507-
this._use_classes = false;
508-
509548
this.bold = false;
549+
this.faint = false;
510550
this.italic = false;
511551
this.underline = false;
512552
this.fg = this.bg = null;
513553

514554
this._buffer = '';
515555

516-
this._url_whitelist = { http: 1, https: 1 };
556+
this._url_allowlist = { http: 1, https: 1 };
557+
558+
this.boldStyle = 'font-weight:bold';
559+
this.faintStyle = 'opacity:0.7';
560+
this.italicStyle = 'font-style:italic';
561+
this.underlineStyle = 'text-decoration:underline';
517562
}
518563

519564
private with_state(pkt: TextPacket): TextWithAttr {
520565
return {
521566
bold: this.bold,
567+
faint: this.faint,
522568
italic: this.italic,
523569
underline: this.underline,
524570
fg: this.fg,
@@ -540,18 +586,27 @@ export default class AnsiUp {
540586
const sgr_cmd_str = sgr_cmds.shift();
541587
const num = parseInt(sgr_cmd_str, 10);
542588

589+
// TODO
590+
// AT SOME POINT, JUST CONVERT TO A LOOKUP TABLE
543591
if (isNaN(num) || num === 0) {
544-
this.fg = this.bg = null;
592+
this.fg = null;
593+
this.bg = null;
545594
this.bold = false;
595+
this.faint = false;
546596
this.italic = false;
547597
this.underline = false;
548598
} else if (num === 1) {
549599
this.bold = true;
600+
} else if (num === 2) {
601+
this.faint = true;
550602
} else if (num === 3) {
551603
this.italic = true;
552604
} else if (num === 4) {
553605
this.underline = true;
606+
} else if (num === 21) {
607+
this.bold = false;
554608
} else if (num === 22) {
609+
this.faint = false;
555610
this.bold = false;
556611
} else if (num === 23) {
557612
this.italic = false;
@@ -612,13 +667,13 @@ export default class AnsiUp {
612667
}
613668

614669
private transform_to_html(fragment: TextWithAttr): string {
615-
const txt = fragment.text;
670+
let txt = fragment.text;
616671

617672
if (txt.length === 0) {
618673
return txt;
619674
}
620675

621-
// txt = this.escape_txt_for_html(txt);
676+
txt = this.escape_txt_for_html(txt);
622677

623678
// If colors not set, default style is used
624679
if (!fragment.bold && !fragment.italic && !fragment.underline && fragment.fg === null && fragment.bg === null) {
@@ -631,21 +686,26 @@ export default class AnsiUp {
631686
const fg = fragment.fg;
632687
const bg = fragment.bg;
633688

634-
// Note on bold: https://stackoverflow.com/questions/6737005/what-are-some-advantages-to-using-span-style-font-weightbold-rather-than-b?rq=1
635-
if (fragment.bold) {
636-
styles.push('font-weight:bold');
637-
}
689+
if (!this._use_classes) {
690+
// USE INLINE STYLES
638691

639-
if (fragment.italic) {
640-
styles.push('font-style:italic');
641-
}
692+
// Note on bold: https://stackoverflow.com/questions/6737005/what-are-some-advantages-to-using-span-style-font-weightbold-rather-than-b?rq=1
693+
if (fragment.bold) {
694+
styles.push(this._boldStyle);
695+
}
642696

643-
if (fragment.underline) {
644-
styles.push('text-decoration:underline');
645-
}
697+
if (fragment.faint) {
698+
styles.push(this._faintStyle);
699+
}
700+
701+
if (fragment.italic) {
702+
styles.push(this._italicStyle);
703+
}
704+
705+
if (fragment.underline) {
706+
styles.push(this._underlineStyle);
707+
}
646708

647-
if (!this._use_classes) {
648-
// USE INLINE STYLES
649709
if (fg) {
650710
styles.push(`color:rgb(${fg.rgb.join(',')})`);
651711
}
@@ -654,6 +714,24 @@ export default class AnsiUp {
654714
}
655715
} else {
656716
// USE CLASSES
717+
718+
// Note on bold: https://stackoverflow.com/questions/6737005/what-are-some-advantages-to-using-span-style-font-weightbold-rather-than-b?rq=1
719+
if (fragment.bold) {
720+
classes.push("ansi-bold");
721+
}
722+
723+
if (fragment.faint) {
724+
classes.push("ansi-faint");
725+
}
726+
727+
if (fragment.italic) {
728+
classes.push("ansi-italic");
729+
}
730+
731+
if (fragment.underline) {
732+
classes.push("ansi-underline");
733+
}
734+
657735
if (fg) {
658736
if (fg.class_name !== 'truecolor') {
659737
classes.push(`${fg.class_name}-fg`);
@@ -691,7 +769,7 @@ export default class AnsiUp {
691769
return '';
692770
}
693771

694-
if (!this._url_whitelist[parts[0]]) {
772+
if (!this._url_allowlist[parts[0]]) {
695773
return '';
696774
}
697775

0 commit comments

Comments
 (0)