|
@@ -6,6 +6,7 @@ interface ConsoleState {
|
|
foregroundColor: string | null;
|
|
foregroundColor: string | null;
|
|
backgroundColor: string | null;
|
|
backgroundColor: string | null;
|
|
carriageReturn: boolean;
|
|
carriageReturn: boolean;
|
|
|
|
+ lines: string[];
|
|
secret: boolean;
|
|
secret: boolean;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -18,6 +19,7 @@ export class ColoredConsole {
|
|
foregroundColor: null,
|
|
foregroundColor: null,
|
|
backgroundColor: null,
|
|
backgroundColor: null,
|
|
carriageReturn: false,
|
|
carriageReturn: false,
|
|
|
|
+ lines: [],
|
|
secret: false,
|
|
secret: false,
|
|
};
|
|
};
|
|
|
|
|
|
@@ -27,26 +29,13 @@ export class ColoredConsole {
|
|
return this.targetElement.innerText;
|
|
return this.targetElement.innerText;
|
|
}
|
|
}
|
|
|
|
|
|
- addLine(line: string) {
|
|
|
|
|
|
+ processLine(line: string): Element {
|
|
// @ts-expect-error
|
|
// @ts-expect-error
|
|
const re = /(?:\033|\\033)(?:\[(.*?)[@-~]|\].*?(?:\007|\033\\))/g;
|
|
const re = /(?:\033|\\033)(?:\[(.*?)[@-~]|\].*?(?:\007|\033\\))/g;
|
|
let i = 0;
|
|
let i = 0;
|
|
|
|
|
|
- if (this.state.carriageReturn) {
|
|
|
|
- if (line !== "\n") {
|
|
|
|
- // don't remove if \r\n
|
|
|
|
- this.targetElement.removeChild(this.targetElement.lastChild!);
|
|
|
|
- }
|
|
|
|
- this.state.carriageReturn = false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (line.includes("\r")) {
|
|
|
|
- this.state.carriageReturn = true;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
const lineSpan = document.createElement("span");
|
|
const lineSpan = document.createElement("span");
|
|
lineSpan.classList.add("line");
|
|
lineSpan.classList.add("line");
|
|
- this.targetElement.appendChild(lineSpan);
|
|
|
|
|
|
|
|
const addSpan = (content: string) => {
|
|
const addSpan = (content: string) => {
|
|
if (content === "") return;
|
|
if (content === "") return;
|
|
@@ -179,17 +168,52 @@ export class ColoredConsole {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ addSpan(line.substring(i));
|
|
|
|
+ return lineSpan;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ processLines() {
|
|
const atBottom =
|
|
const atBottom =
|
|
this.targetElement.scrollTop >
|
|
this.targetElement.scrollTop >
|
|
this.targetElement.scrollHeight - this.targetElement.offsetHeight - 50;
|
|
this.targetElement.scrollHeight - this.targetElement.offsetHeight - 50;
|
|
|
|
+ const prevCarriageReturn = this.state.carriageReturn;
|
|
|
|
+ const fragment = document.createDocumentFragment();
|
|
|
|
|
|
- addSpan(line.substring(i));
|
|
|
|
|
|
+ if (this.state.lines.length == 0) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (const line of this.state.lines) {
|
|
|
|
+ if (this.state.carriageReturn && line !== "\n") {
|
|
|
|
+ if (fragment.childElementCount) {
|
|
|
|
+ fragment.removeChild(fragment.lastChild!);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ fragment.appendChild(this.processLine(line));
|
|
|
|
+ this.state.carriageReturn = line.includes("\r");
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (prevCarriageReturn && this.state.lines[0] !== "\n") {
|
|
|
|
+ this.targetElement.replaceChild(fragment, this.targetElement.lastChild!);
|
|
|
|
+ } else {
|
|
|
|
+ this.targetElement.appendChild(fragment);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ this.state.lines = [];
|
|
|
|
|
|
// Keep scroll at bottom
|
|
// Keep scroll at bottom
|
|
if (atBottom) {
|
|
if (atBottom) {
|
|
this.targetElement.scrollTop = this.targetElement.scrollHeight;
|
|
this.targetElement.scrollTop = this.targetElement.scrollHeight;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ addLine(line: string) {
|
|
|
|
+ // Processing of lines is deferred for performance reasons
|
|
|
|
+ if (this.state.lines.length == 0) {
|
|
|
|
+ setTimeout(() => this.processLines(), 0);
|
|
|
|
+ }
|
|
|
|
+ this.state.lines.push(line);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
export const coloredConsoleStyles = `
|
|
export const coloredConsoleStyles = `
|