Skip to content

Commit df4c1ab

Browse files
committed
Implement terminal replay event
1 parent e292dca commit df4c1ab

File tree

1 file changed

+63
-8
lines changed

1 file changed

+63
-8
lines changed

ci/dev/vscode.patch

+63-8
Original file line numberDiff line numberDiff line change
@@ -1466,10 +1466,10 @@ index 0000000000000000000000000000000000000000..6ce56bec114a6d8daf5dd3ded945ea78
14661466
+}
14671467
diff --git a/src/vs/server/node/channel.ts b/src/vs/server/node/channel.ts
14681468
new file mode 100644
1469-
index 0000000000000000000000000000000000000000..91a932b613c473cd13dfddbde2942aeebf4bb84c
1469+
index 0000000000000000000000000000000000000000..cb3a45fda10a6bcbff73275b5734641b3319cc9b
14701470
--- /dev/null
14711471
+++ b/src/vs/server/node/channel.ts
1472-
@@ -0,0 +1,780 @@
1472+
@@ -0,0 +1,828 @@
14731473
+import { field, logger } from '@coder/logger';
14741474
+import { Server } from '@coder/node-browser';
14751475
+import * as os from 'os';
@@ -1884,6 +1884,14 @@ index 0000000000000000000000000000000000000000..91a932b613c473cd13dfddbde2942aee
18841884
+ private readonly _onDispose = new Emitter<void>();
18851885
+ public get onDispose(): Event<void> { return this._onDispose.event; }
18861886
+
1887+
+ // These are replayed when a client reconnects.
1888+
+ private cols: number;
1889+
+ private rows: number;
1890+
+ private replayData: string[] = [];
1891+
+ // This is based on string length and is pretty arbitrary.
1892+
+ private readonly maxReplayData = 10000;
1893+
+ private totalReplayData = 0;
1894+
+
18871895
+ private buffering = false;
18881896
+ private readonly _onEvent = new Emitter<terminal.IRemoteTerminalProcessEvent>({
18891897
+ // Don't bind to data until something is listening.
@@ -1894,6 +1902,23 @@ index 0000000000000000000000000000000000000000..91a932b613c473cd13dfddbde2942aee
18941902
+ this.bufferer.startBuffering(this.id, this.process.onProcessData);
18951903
+ }
18961904
+ },
1905+
+
1906+
+ // Replay stored events.
1907+
+ onFirstListenerDidAdd: () => {
1908+
+ if (this.replayData.length === 0) {
1909+
+ return;
1910+
+ }
1911+
+
1912+
+ logger.debug('Terminal replaying', field('id', this.id));
1913+
+ this._onEvent.fire({
1914+
+ type: 'replay',
1915+
+ events: [{
1916+
+ cols: this.cols,
1917+
+ rows: this.rows,
1918+
+ data: this.replayData.join(""),
1919+
+ }]
1920+
+ });
1921+
+ }
18971922
+ });
18981923
+
18991924
+ public get onEvent(): Event<terminal.IRemoteTerminalProcessEvent> { return this._onEvent.event; }
@@ -1904,6 +1929,33 @@ index 0000000000000000000000000000000000000000..91a932b613c473cd13dfddbde2942aee
19041929
+ type: 'data',
19051930
+ data,
19061931
+ });
1932+
+
1933+
+ this.replayData.push(data);
1934+
+ this.totalReplayData += data.length;
1935+
+
1936+
+ let overflow = this.totalReplayData - this.maxReplayData;
1937+
+ if (overflow <= 0) {
1938+
+ return;
1939+
+ }
1940+
+
1941+
+ // Drop events until doing so would put us under budget.
1942+
+ let deleteCount = 0;
1943+
+ for (; deleteCount < this.replayData.length
1944+
+ && this.replayData[deleteCount].length <= overflow; ++deleteCount) {
1945+
+ overflow -= this.replayData[deleteCount].length;
1946+
+ }
1947+
+
1948+
+ if (deleteCount > 0) {
1949+
+ this.replayData.splice(0, deleteCount);
1950+
+ }
1951+
+
1952+
+ // Dropping any more events would put us under budget; trim the first event
1953+
+ // instead if still over budget.
1954+
+ if (overflow > 0 && this.replayData.length > 0) {
1955+
+ this.replayData[0] = this.replayData[0].substring(overflow);
1956+
+ }
1957+
+
1958+
+ this.totalReplayData = this.replayData.reduce((p, c) => p + c.length, 0);
19071959
+ });
19081960
+
19091961
+ public get pid(): number {
@@ -1924,11 +1976,14 @@ index 0000000000000000000000000000000000000000..91a932b613c473cd13dfddbde2942aee
19241976
+ this.workspaceId = args.workspaceId;
19251977
+ this.workspaceName = args.workspaceName;
19261978
+
1979+
+ this.cols = args.cols;
1980+
+ this.rows = args.rows;
1981+
+
19271982
+ this.process = new TerminalProcess(
19281983
+ config,
19291984
+ config.cwd,
1930-
+ args.cols,
1931-
+ args.rows,
1985+
+ this.cols,
1986+
+ this.rows,
19321987
+ env,
19331988
+ process.env as platform.IProcessEnvironment, // Environment used for `findExecutable`.
19341989
+ false, // windowsEnableConpty: boolean,
@@ -1962,10 +2017,6 @@ index 0000000000000000000000000000000000000000..91a932b613c473cd13dfddbde2942aee
19622017
+ this.dispose();
19632018
+ });
19642019
+
1965-
+ // TODO: replay event
1966-
+ // type: 'replay';
1967-
+ // events: ReplayEntry[];
1968-
+
19692020
+ // TODO: exec command event
19702021
+ // type: 'execCommand';
19712022
+ // reqId: number;
@@ -1977,9 +2028,11 @@ index 0000000000000000000000000000000000000000..91a932b613c473cd13dfddbde2942aee
19772028
+ }
19782029
+
19792030
+ public dispose() {
2031+
+ logger.debug('Terminal disposing', field('id', this.id));
19802032
+ this._onEvent.dispose();
19812033
+ this.bufferer.dispose();
19822034
+ this.process.dispose();
2035+
+ this.process.shutdown(true);
19832036
+ this._onDispose.fire();
19842037
+ this._onDispose.dispose();
19852038
+ }
@@ -2005,6 +2058,8 @@ index 0000000000000000000000000000000000000000..91a932b613c473cd13dfddbde2942aee
20052058
+ }
20062059
+
20072060
+ public resize(cols: number, rows: number): void {
2061+
+ this.cols = cols;
2062+
+ this.rows = rows;
20082063
+ return this.process.resize(cols, rows);
20092064
+ }
20102065
+}

0 commit comments

Comments
 (0)