1 | import { ColoredConsole, coloredConsoleStyles } from "../util/console-color";
|
2 | import { sleep } from "../util/sleep";
|
3 | import { LineBreakTransformer } from "../util/line-break-transformer";
|
4 | import { TimestampTransformer } from "../util/timestamp-transformer";
|
5 | export class EwtConsole extends HTMLElement {
|
6 | constructor() {
|
7 | super(...arguments);
|
8 | this.allowInput = true;
|
9 | }
|
10 | logs() {
|
11 | var _a;
|
12 | return ((_a = this._console) === null || _a === void 0 ? void 0 : _a.logs()) || "";
|
13 | }
|
14 | connectedCallback() {
|
15 | if (this._console) {
|
16 | return;
|
17 | }
|
18 | const shadowRoot = this.attachShadow({ mode: "open" });
|
19 | shadowRoot.innerHTML = `
|
20 | <style>
|
21 | :host, input {
|
22 | background-color: #1c1c1c;
|
23 | color: #ddd;
|
24 | font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier,
|
25 | monospace;
|
26 | line-height: 1.45;
|
27 | display: flex;
|
28 | flex-direction: column;
|
29 | }
|
30 | form {
|
31 | display: flex;
|
32 | align-items: center;
|
33 | padding: 0 8px 0 16px;
|
34 | }
|
35 | input {
|
36 | flex: 1;
|
37 | padding: 4px;
|
38 | margin: 0 8px;
|
39 | border: 0;
|
40 | outline: none;
|
41 | }
|
42 | ${coloredConsoleStyles}
|
43 | </style>
|
44 | <div class="log"></div>
|
45 | ${this.allowInput
|
46 | ? `<form>
|
47 | >
|
48 | <input autofocus>
|
49 | </form>
|
50 | `
|
51 | : ""}
|
52 | `;
|
53 | this._console = new ColoredConsole(this.shadowRoot.querySelector("div"));
|
54 | if (this.allowInput) {
|
55 | const input = this.shadowRoot.querySelector("input");
|
56 | this.addEventListener("click", () => {
|
57 | var _a;
|
58 |
|
59 | if (((_a = getSelection()) === null || _a === void 0 ? void 0 : _a.toString()) === "") {
|
60 | input.focus();
|
61 | }
|
62 | });
|
63 | input.addEventListener("keydown", (ev) => {
|
64 | if (ev.key === "Enter") {
|
65 | ev.preventDefault();
|
66 | ev.stopPropagation();
|
67 | this._sendCommand();
|
68 | }
|
69 | });
|
70 | }
|
71 | const abortController = new AbortController();
|
72 | const connection = this._connect(abortController.signal);
|
73 | this._cancelConnection = () => {
|
74 | abortController.abort();
|
75 | return connection;
|
76 | };
|
77 | }
|
78 | async _connect(abortSignal) {
|
79 | this.logger.debug("Starting console read loop");
|
80 | try {
|
81 | await this.port
|
82 | .readable.pipeThrough(new TextDecoderStream(), {
|
83 | signal: abortSignal,
|
84 | })
|
85 | .pipeThrough(new TransformStream(new LineBreakTransformer()))
|
86 | .pipeThrough(new TransformStream(new TimestampTransformer()))
|
87 | .pipeTo(new WritableStream({
|
88 | write: (chunk) => {
|
89 | this._console.addLine(chunk.replace("\r", ""));
|
90 | },
|
91 | }));
|
92 | if (!abortSignal.aborted) {
|
93 | this._console.addLine("");
|
94 | this._console.addLine("");
|
95 | this._console.addLine("Terminal disconnected");
|
96 | }
|
97 | }
|
98 | catch (e) {
|
99 | this._console.addLine("");
|
100 | this._console.addLine("");
|
101 | this._console.addLine(`Terminal disconnected: ${e}`);
|
102 | }
|
103 | finally {
|
104 | await sleep(100);
|
105 | this.logger.debug("Finished console read loop");
|
106 | }
|
107 | }
|
108 | async _sendCommand() {
|
109 | const input = this.shadowRoot.querySelector("input");
|
110 | const command = input.value;
|
111 | const encoder = new TextEncoder();
|
112 | const writer = this.port.writable.getWriter();
|
113 | await writer.write(encoder.encode(command + "\r\n"));
|
114 | this._console.addLine(`> ${command}\r\n`);
|
115 | input.value = "";
|
116 | input.focus();
|
117 | try {
|
118 | writer.releaseLock();
|
119 | }
|
120 | catch (err) {
|
121 | console.error("Ignoring release lock error", err);
|
122 | }
|
123 | }
|
124 | async disconnect() {
|
125 | if (this._cancelConnection) {
|
126 | await this._cancelConnection();
|
127 | this._cancelConnection = undefined;
|
128 | }
|
129 | }
|
130 | async reset() {
|
131 | this.logger.debug("Triggering reset");
|
132 | await this.port.setSignals({
|
133 | dataTerminalReady: false,
|
134 | requestToSend: true,
|
135 | });
|
136 | await sleep(250);
|
137 | await this.port.setSignals({
|
138 | dataTerminalReady: false,
|
139 | requestToSend: false,
|
140 | });
|
141 | await sleep(250);
|
142 | await new Promise((resolve) => setTimeout(resolve, 1000));
|
143 | }
|
144 | }
|
145 | customElements.define("ewt-console", EwtConsole);
|