Skip to content

Commit

Permalink
Merge pull request #116449 from microsoft/tyriar_megan_reconnect
Browse files Browse the repository at this point in the history
Local terminal reconnection
  • Loading branch information
Tyriar authored Feb 22, 2021
2 parents 218ffbf + ce7cd0a commit d6846fa
Show file tree
Hide file tree
Showing 35 changed files with 897 additions and 239 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import { assertNoRpc } from '../utils';
extensionContext = (global as any).testExtensionContext;

const config = workspace.getConfiguration('terminal.integrated');
// Disable conpty in integration tests because of https://github.com/microsoft/vscode/issues/76548
await config.update('windowsEnableConpty', false, ConfigurationTarget.Global);
// Disable exit alerts as tests may trigger then and we're not testing the notifications
await config.update('showExitAlert', false, ConfigurationTarget.Global);
// Canvas may cause problems when running in a container
Expand Down Expand Up @@ -637,10 +639,7 @@ import { assertNoRpc } from '../utils';
'~c2~c1'
];
disposables.push(window.onDidWriteTerminalData(e => {
try {
equal(terminal, e.terminal);
} catch (e) {
done(e);
if (terminal !== e.terminal) {
return;
}
// Multiple expected could show up in the same data event
Expand Down Expand Up @@ -683,10 +682,7 @@ import { assertNoRpc } from '../utils';
'~c2~'
];
disposables.push(window.onDidWriteTerminalData(e => {
try {
equal(terminal, e.terminal);
} catch (e) {
done(e);
if (terminal !== e.terminal) {
return;
}
// Multiple expected could show up in the same data event
Expand Down Expand Up @@ -728,10 +724,7 @@ import { assertNoRpc } from '../utils';
'~b1~'
];
disposables.push(window.onDidWriteTerminalData(e => {
try {
equal(terminal, e.terminal);
} catch (e) {
done(e);
if (terminal !== e.terminal) {
return;
}
// Multiple expected could show up in the same data event
Expand Down Expand Up @@ -770,10 +763,7 @@ import { assertNoRpc } from '../utils';
'~b2~'
];
disposables.push(window.onDidWriteTerminalData(e => {
try {
equal(terminal, e.terminal);
} catch (e) {
done(e);
if (terminal !== e.terminal) {
return;
}
// Multiple expected could show up in the same data event
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "code-oss-dev",
"version": "1.54.0",
"distro": "15d06a28bcd9dc439ef80df6851d875624b6ff0f",
"distro": "79bf0c38866670404869fbc506d1622e551d27b6",
"author": {
"name": "Microsoft Corporation"
},
Expand Down
19 changes: 19 additions & 0 deletions src/vs/base/common/async.ts
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,25 @@ export class Barrier {
}
}

/**
* A barrier that is initially closed and then becomes opened permanently after a certain period of
* time or when open is called explicitly
*/
export class AutoOpenBarrier extends Barrier {

private readonly _timeout: any;

constructor(autoOpenTimeMs: number) {
super();
this._timeout = setTimeout(() => this.open(), autoOpenTimeMs);
}

open(): void {
clearTimeout(this._timeout);
super.open();
}
}

export function timeout(millis: number): CancelablePromise<void>;
export function timeout(millis: number, token: CancellationToken): Promise<void>;
export function timeout(millis: number, token?: CancellationToken): CancelablePromise<void> | Promise<void> {
Expand Down
16 changes: 16 additions & 0 deletions src/vs/platform/terminal/common/environmentVariable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

export enum EnvironmentVariableMutatorType {
Replace = 1,
Append = 2,
Prepend = 3
}
export interface IEnvironmentVariableMutator {
readonly value: string;
readonly type: EnvironmentVariableMutatorType;
}
/** [variable, mutator] */
export type ISerializableEnvironmentVariableCollection = [string, IEnvironmentVariableMutator][];
83 changes: 66 additions & 17 deletions src/vs/platform/terminal/common/terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,45 @@
import { Event } from 'vs/base/common/event';
import { IProcessEnvironment } from 'vs/base/common/platform';
import { URI } from 'vs/base/common/uri';
import { IGetTerminalLayoutInfoArgs, IPtyHostProcessReplayEvent, ISetTerminalLayoutInfoArgs } from 'vs/platform/terminal/common/terminalProcess';

export interface IRawTerminalInstanceLayoutInfo<T> {
relativeSize: number;
terminal: T;
}
export type ITerminalInstanceLayoutInfoById = IRawTerminalInstanceLayoutInfo<number>;
export type ITerminalInstanceLayoutInfo = IRawTerminalInstanceLayoutInfo<IPtyHostAttachTarget>;

export interface IRawTerminalTabLayoutInfo<T> {
isActive: boolean;
activePersistentTerminalId: number | undefined;
terminals: IRawTerminalInstanceLayoutInfo<T>[];
}

export type ITerminalTabLayoutInfoById = IRawTerminalTabLayoutInfo<number>;
export type ITerminalTabLayoutInfo = IRawTerminalTabLayoutInfo<IPtyHostAttachTarget | null>;

export interface IRawTerminalsLayoutInfo<T> {
tabs: IRawTerminalTabLayoutInfo<T>[];
}

export interface IPtyHostAttachTarget {
id: number;
pid: number;
title: string;
cwd: string;
workspaceId: string;
workspaceName: string;
isOrphan: boolean;
}

export type ITerminalsLayoutInfo = IRawTerminalsLayoutInfo<IPtyHostAttachTarget | null>;
export type ITerminalsLayoutInfoById = IRawTerminalsLayoutInfo<number>;

export interface IRawTerminalInstanceLayoutInfo<T> {
relativeSize: number;
terminal: T;
}

export enum TerminalIpcChannels {
/**
Expand Down Expand Up @@ -39,6 +78,10 @@ export interface IPtyService {
readonly onProcessTitleChanged: Event<{ id: number, event: string }>;
readonly onProcessOverrideDimensions: Event<{ id: number, event: ITerminalDimensionsOverride | undefined }>;
readonly onProcessResolvedShellLaunchConfig: Event<{ id: number, event: IShellLaunchConfig }>;
readonly onProcessReplay: Event<{ id: number, event: IPtyHostProcessReplayEvent }>;

restartPtyHost?(): Promise<void>;
shutdownAll?(): Promise<void>;

createProcess(
shellLaunchConfig: IShellLaunchConfig,
Expand All @@ -47,28 +90,23 @@ export interface IPtyService {
rows: number,
env: IProcessEnvironment,
executableEnv: IProcessEnvironment,
windowsEnableConpty: boolean
windowsEnableConpty: boolean,
workspaceId: string,
workspaceName: string
): Promise<number>;
attachToProcess(id: number): Promise<void>;

shutdownAll?(): Promise<void>;

start(id: number): Promise<ITerminalLaunchError | { remoteTerminalId: number; } | undefined>;

start(id: number): Promise<ITerminalLaunchError | { persistentTerminalId: number; } | undefined>;
shutdown(id: number, immediate: boolean): Promise<void>;

input(id: number, data: string): Promise<void>;

resize(id: number, cols: number, rows: number): Promise<void>;

acknowledgeDataEvent(id: number, charCount: number): Promise<void>;

getInitialCwd(id: number): Promise<string>;

getCwd(id: number): Promise<string>;

getLatency(id: number): Promise<number>;
acknowledgeDataEvent(id: number, charCount: number): Promise<void>;

restartPtyHost?(): Promise<void>;
setTerminalLayoutInfo(args: ISetTerminalLayoutInfoArgs): void;
getTerminalLayoutInfo(args: IGetTerminalLayoutInfoArgs): Promise<ITerminalsLayoutInfo | undefined>;
}

export enum HeartbeatConstants {
Expand All @@ -92,7 +130,7 @@ export enum HeartbeatConstants {
* process. This short circuits the standard wait timeouts to tell the user sooner and only
* create process is handled to avoid additional perf overhead.
*/
CreateProcessTimeout = 2000
CreateProcessTimeout = 5000
}

export interface IHeartbeatService {
Expand Down Expand Up @@ -157,9 +195,9 @@ export interface IShellLaunchConfig {
extHostTerminalId?: string;

/**
* This is a terminal that attaches to an already running remote terminal.
* This is a terminal that attaches to an already running terminal.
*/
remoteAttach?: { id: number; pid: number; title: string; cwd: string; };
attachPersistentTerminal?: { id: number; pid: number; title: string; cwd: string; };

/**
* Whether the terminal process environment should be exactly as provided in
Expand Down Expand Up @@ -218,7 +256,7 @@ export interface ITerminalChildProcess {
* @returns undefined when the process was successfully started, otherwise an object containing
* information on what went wrong.
*/
start(): Promise<ITerminalLaunchError | { remoteTerminalId: number } | undefined>;
start(): Promise<ITerminalLaunchError | { persistentTerminalId: number } | undefined>;

/**
* Shutdown the terminal process.
Expand All @@ -243,6 +281,17 @@ export interface ITerminalChildProcess {
getLatency(): Promise<number>;
}

export const enum LocalReconnectConstants {
/**
* If there is no reconnection within this time-frame, consider the connection permanently closed...
*/
ReconnectionGraceTime = 5000, // 5 seconds
/**
* Maximal grace time between the first and the last reconnection...
*/
ReconnectionShortGraceTime = 1000, // 1 second
}

export const enum FlowControlConstants {
/**
* The number of _unacknowledged_ chars to have been sent before the pty is paused in order for
Expand Down
76 changes: 76 additions & 0 deletions src/vs/platform/terminal/common/terminalProcess.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { UriComponents } from 'vs/base/common/uri';
import { IRawTerminalTabLayoutInfo, ITerminalEnvironment, ITerminalTabLayoutInfoById } from 'vs/platform/terminal/common/terminal';
import { ISerializableEnvironmentVariableCollection } from 'vs/platform/terminal/common/environmentVariable';

export interface IShellLaunchConfigDto {
name?: string;
executable?: string;
args?: string[] | string;
cwd?: string | UriComponents;
env?: { [key: string]: string | null; };
hideFromUser?: boolean;
}

export interface ISingleTerminalConfiguration<T> {
userValue: T | undefined;
value: T | undefined;
defaultValue: T | undefined;
}

export interface ICompleteTerminalConfiguration {
'terminal.integrated.automationShell.windows': ISingleTerminalConfiguration<string | string[]>;
'terminal.integrated.automationShell.osx': ISingleTerminalConfiguration<string | string[]>;
'terminal.integrated.automationShell.linux': ISingleTerminalConfiguration<string | string[]>;
'terminal.integrated.shell.windows': ISingleTerminalConfiguration<string | string[]>;
'terminal.integrated.shell.osx': ISingleTerminalConfiguration<string | string[]>;
'terminal.integrated.shell.linux': ISingleTerminalConfiguration<string | string[]>;
'terminal.integrated.shellArgs.windows': ISingleTerminalConfiguration<string | string[]>;
'terminal.integrated.shellArgs.osx': ISingleTerminalConfiguration<string | string[]>;
'terminal.integrated.shellArgs.linux': ISingleTerminalConfiguration<string | string[]>;
'terminal.integrated.env.windows': ISingleTerminalConfiguration<ITerminalEnvironment>;
'terminal.integrated.env.osx': ISingleTerminalConfiguration<ITerminalEnvironment>;
'terminal.integrated.env.linux': ISingleTerminalConfiguration<ITerminalEnvironment>;
'terminal.integrated.inheritEnv': boolean;
'terminal.integrated.cwd': string;
'terminal.integrated.detectLocale': 'auto' | 'off' | 'on';
'terminal.flowControl': boolean;
}

export type ITerminalEnvironmentVariableCollections = [string, ISerializableEnvironmentVariableCollection][];

export interface IWorkspaceFolderData {
uri: UriComponents;
name: string;
index: number;
}

export interface ISetTerminalLayoutInfoArgs {
workspaceId: string;
tabs: ITerminalTabLayoutInfoById[];
}

export interface IGetTerminalLayoutInfoArgs {
workspaceId: string;
}

export interface IPtyHostDescriptionDto {
id: number;
pid: number;
title: string;
cwd: string;
workspaceId: string;
workspaceName: string;
isOrphan: boolean;
}

export type ITerminalTabLayoutInfoDto = IRawTerminalTabLayoutInfo<IPtyHostDescriptionDto>;

export interface ReplayEntry { cols: number; rows: number; data: string; }
export interface IPtyHostProcessReplayEvent {
events: ReplayEntry[];
}
Loading

0 comments on commit d6846fa

Please sign in to comment.