Skip to content

Commit

Permalink
Set default profile in exthost from renderer
Browse files Browse the repository at this point in the history
  • Loading branch information
Tyriar committed May 13, 2021
1 parent 963eff6 commit 6d70e72
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 112 deletions.
28 changes: 24 additions & 4 deletions src/vs/workbench/api/browser/mainThreadTerminalService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ import { ITerminalExternalLinkProvider, ITerminalInstance, ITerminalInstanceServ
import { TerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy';
import { IEnvironmentVariableService, ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { deserializeEnvironmentVariableCollection, serializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
import { IStartExtensionTerminalRequest, ITerminalProcessExtHostProxy, TitleEventSource } from 'vs/workbench/contrib/terminal/common/terminal';
import { IStartExtensionTerminalRequest, ITerminalProcessExtHostProxy, ITerminalProfileResolverService, TitleEventSource } from 'vs/workbench/contrib/terminal/common/terminal';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { withNullAsUndefined } from 'vs/base/common/types';
import { OperatingSystem, OS } from 'vs/base/common/platform';

@extHostNamedCustomer(MainContext.MainThreadTerminalService)
export class MainThreadTerminalService implements MainThreadTerminalServiceShape {
Expand All @@ -39,15 +42,19 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
*/
private _linkProvider: IDisposable | undefined;

private _os: OperatingSystem = OS;

constructor(
extHostContext: IExtHostContext,
private readonly _extHostContext: IExtHostContext,
@ITerminalService private readonly _terminalService: ITerminalService,
@ITerminalInstanceService readonly terminalInstanceService: ITerminalInstanceService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@IEnvironmentVariableService private readonly _environmentVariableService: IEnvironmentVariableService,
@ILogService private readonly _logService: ILogService,
@ITerminalProfileResolverService private readonly _terminalProfileResolverService: ITerminalProfileResolverService,
@IRemoteAgentService remoteAgentService: IRemoteAgentService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTerminalService);
this._proxy = _extHostContext.getProxy(ExtHostContext.ExtHostTerminalService);

// ITerminalService listeners
this._toDispose.add(_terminalService.onInstanceCreated((instance) => {
Expand Down Expand Up @@ -80,14 +87,27 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
this._proxy.$initEnvironmentVariableCollections(serializedCollections);
}

this._terminalService.extHostReady(extHostContext.remoteAuthority!); // TODO@Tyriar: remove null assertion
remoteAgentService.getEnvironment().then(async env => {
this._os = env?.os || OS;
this._updateDefaultProfile();
});
this._terminalService.onDidChangeAvailableProfiles(() => this._updateDefaultProfile());

this._terminalService.extHostReady(_extHostContext.remoteAuthority!); // TODO@Tyriar: remove null assertion
}

public dispose(): void {
this._toDispose.dispose();
this._linkProvider?.dispose();
}

private async _updateDefaultProfile() {
const remoteAuthority = withNullAsUndefined(this._extHostContext.remoteAuthority);
const defaultProfile = this._terminalProfileResolverService.getDefaultProfile({ remoteAuthority, os: this._os });
const defaultAutomationProfile = this._terminalProfileResolverService.getDefaultProfile({ remoteAuthority, os: this._os, allowAutomationShell: true });
this._proxy.$acceptDefaultProfile(...await Promise.all([defaultProfile, defaultAutomationProfile]));
}

private _getTerminalId(id: TerminalIdentifier): number | undefined {
if (typeof id === 'number') {
return id;
Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/api/common/extHost.api.impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
get uriScheme() { return initData.environment.appUriScheme; },
get clipboard(): vscode.Clipboard { return extHostClipboard.value; },
get shell() {
return extHostTerminalService.getDefaultShell(false, configProvider);
return extHostTerminalService.getDefaultShell(false);
},
get isTelemetryEnabled() {
return extHostTelemetry.getTelemetryEnabled();
Expand Down
3 changes: 2 additions & 1 deletion src/vs/workbench/api/common/extHost.protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import { IRemoteConnectionData, RemoteAuthorityResolverErrorCode, ResolverResult
import { ProvidedPortAttributes, TunnelCreationOptions, TunnelOptions, TunnelProviderFeatures } from 'vs/platform/remote/common/tunnel';
import { ClassifiedEvent, GDPRClassification, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings';
import { ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
import { IShellLaunchConfig, IShellLaunchConfigDto, ITerminalDimensions, ITerminalEnvironment, ITerminalLaunchError } from 'vs/platform/terminal/common/terminal';
import { IShellLaunchConfig, IShellLaunchConfigDto, ITerminalDimensions, ITerminalEnvironment, ITerminalLaunchError, ITerminalProfile } from 'vs/platform/terminal/common/terminal';
import { ThemeColor } from 'vs/platform/theme/common/themeService';
import { IExtensionIdWithVersion } from 'vs/platform/userDataSync/common/extensionsStorageSync';
import { WorkspaceTrustRequestOptions } from 'vs/platform/workspace/common/workspaceTrust';
Expand Down Expand Up @@ -1708,6 +1708,7 @@ export interface ExtHostTerminalServiceShape {
$provideLinks(id: number, line: string): Promise<ITerminalLinkDto[]>;
$activateLink(id: number, linkId: number): void;
$initEnvironmentVariableCollections(collections: [string, ISerializableEnvironmentVariableCollection][]): void;
$acceptDefaultProfile(profile: ITerminalProfile, automationProfile: ITerminalProfile): void;
}

export interface ExtHostSCMShape {
Expand Down
47 changes: 27 additions & 20 deletions src/vs/workbench/api/common/extHostTerminalService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import type * as vscode from 'vscode';
import { Event, Emitter } from 'vs/base/common/event';
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, ITerminalDimensionsDto, ITerminalLinkDto, TerminalIdentifier, IShellAndArgsDto } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { URI } from 'vs/base/common/uri';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
Expand All @@ -19,7 +18,7 @@ import { serializeEnvironmentVariableCollection } from 'vs/workbench/contrib/ter
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { generateUuid } from 'vs/base/common/uuid';
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { IShellLaunchConfigDto, ITerminalChildProcess, ITerminalDimensionsOverride, ITerminalEnvironment, ITerminalLaunchError, TerminalShellType } from 'vs/platform/terminal/common/terminal';
import { IShellLaunchConfigDto, ITerminalChildProcess, ITerminalDimensionsOverride, ITerminalEnvironment, ITerminalLaunchError, ITerminalProfile, TerminalShellType } from 'vs/platform/terminal/common/terminal';
import { TerminalDataBufferer } from 'vs/platform/terminal/common/terminalDataBuffering';

export interface IExtHostTerminalService extends ExtHostTerminalServiceShape, IDisposable {
Expand All @@ -39,11 +38,11 @@ export interface IExtHostTerminalService extends ExtHostTerminalServiceShape, ID
createTerminalFromOptions(options: vscode.TerminalOptions, isFeatureTerminal?: boolean): vscode.Terminal;
createExtensionTerminal(options: vscode.ExtensionTerminalOptions): vscode.Terminal;
attachPtyToTerminal(id: number, pty: vscode.Pseudoterminal): void;
getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string;
getDefaultShellArgs(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string[] | string;
getDefaultShell(useAutomationShell: boolean): string;
getDefaultShellArgs(useAutomationShell: boolean): string[] | string;
registerLinkProvider(provider: vscode.TerminalLinkProvider): vscode.Disposable;
getEnvironmentVariableCollection(extension: IExtensionDescription, persistent?: boolean): vscode.EnvironmentVariableCollection;
getDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto>;
getDefaultShellAndArgs(useAutomationShell: boolean): IShellAndArgsDto;
}

export const IExtHostTerminalService = createDecorator<IExtHostTerminalService>('IExtHostTerminalService');
Expand Down Expand Up @@ -292,6 +291,8 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
protected _extensionTerminalAwaitingStart: { [id: number]: { initialDimensions: ITerminalDimensionsDto | undefined } | undefined } = {};
protected _getTerminalPromises: { [id: number]: Promise<ExtHostTerminal | undefined> } = {};
protected _environmentVariableCollections: Map<string, EnvironmentVariableCollection> = new Map();
private _defaultProfile: ITerminalProfile | undefined;
private _defaultAutomationProfile: ITerminalProfile | undefined;

private readonly _bufferer: TerminalDataBufferer;
private readonly _linkProviders: Set<vscode.TerminalLinkProvider> = new Set();
Expand Down Expand Up @@ -335,9 +336,22 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I

public abstract createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal;
public abstract createTerminalFromOptions(options: vscode.TerminalOptions): vscode.Terminal;
public abstract getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string;
public abstract getDefaultShellArgs(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string[] | string;
public abstract getDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto>;
public getDefaultShell(useAutomationShell: boolean): string {
const profile = useAutomationShell ? this._defaultAutomationProfile : this._defaultProfile;
return profile?.path || '';
}

public getDefaultShellArgs(useAutomationShell: boolean): string[] | string {
const profile = useAutomationShell ? this._defaultAutomationProfile : this._defaultProfile;
return profile?.args || [''];
}

public getDefaultShellAndArgs(useAutomationShell: boolean): IShellAndArgsDto {
return {
shell: this.getDefaultShell(useAutomationShell),
args: this.getDefaultShellArgs(useAutomationShell)
};
}

public createExtensionTerminal(options: vscode.ExtensionTerminalOptions): vscode.Terminal {
const terminal = new ExtHostTerminal(this._proxy, generateUuid(), options, options.name);
Expand Down Expand Up @@ -688,6 +702,11 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
});
}

public $acceptDefaultProfile(profile: ITerminalProfile, automationProfile: ITerminalProfile): void {
this._defaultProfile = profile;
this._defaultAutomationProfile = automationProfile;
}

private _setEnvironmentVariableCollection(extensionIdentifier: string, collection: EnvironmentVariableCollection): void {
this._environmentVariableCollections.set(extensionIdentifier, collection);
collection.onDidChangeCollection(() => {
Expand Down Expand Up @@ -776,16 +795,4 @@ export class WorkerExtHostTerminalService extends BaseExtHostTerminalService {
public createTerminalFromOptions(options: vscode.TerminalOptions): vscode.Terminal {
throw new NotSupportedError();
}

public getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string {
throw new NotSupportedError();
}

public getDefaultShellArgs(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string[] | string {
throw new NotSupportedError();
}

public async getDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto> {
throw new NotSupportedError();
}
}
4 changes: 2 additions & 2 deletions src/vs/workbench/api/node/extHostDebugService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ export class ExtHostDebugService extends ExtHostDebugServiceBase {
}

const configProvider = await this._configurationService.getConfigProvider();
const shell = this._terminalService.getDefaultShell(true, configProvider);
const shellArgs = this._terminalService.getDefaultShellArgs(true, configProvider);
const shell = this._terminalService.getDefaultShell(true);
const shellArgs = this._terminalService.getDefaultShellArgs(true);

const shellConfig = JSON.stringify({ shell, shellArgs });
let terminal = await this._integratedTerminalInstances.checkout(shellConfig);
Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/api/node/extHostTask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ export class ExtHostTask extends ExtHostTaskBase {
return result;
}

public $getDefaultShellAndArgs(): Promise<{ shell: string, args: string[] | string | undefined }> {
public async $getDefaultShellAndArgs(): Promise<{ shell: string, args: string[] | string | undefined }> {
return this._terminalService.getDefaultShellAndArgs(true);
}

Expand Down
84 changes: 1 addition & 83 deletions src/vs/workbench/api/node/extHostTerminalService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,18 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import * as platform from 'vs/base/common/platform';
import { withNullAsUndefined } from 'vs/base/common/types';
import { generateUuid } from 'vs/base/common/uuid';
import { getSystemShell, getSystemShellSync } from 'vs/base/node/shell';
import { ILogService } from 'vs/platform/log/common/log';
import { SafeConfigProvider, TerminalSettingId } from 'vs/platform/terminal/common/terminal';
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { IShellAndArgsDto } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostConfigProvider, ExtHostConfiguration, IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
import { ExtHostVariableResolverService } from 'vs/workbench/api/common/extHostDebugService';
import { ExtHostDocumentsAndEditors, IExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { BaseExtHostTerminalService, ExtHostTerminal } from 'vs/workbench/api/common/extHostTerminalService';
import { ExtHostWorkspace, IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
import type * as vscode from 'vscode';

export class ExtHostTerminalService extends BaseExtHostTerminalService {

private _variableResolver: ExtHostVariableResolverService | undefined;
private _lastActiveWorkspace: IWorkspaceFolder | undefined;

private _defaultShell: string | undefined;

constructor(
@IExtHostRpcService extHostRpc: IExtHostRpcService,
@IExtHostConfiguration private _extHostConfiguration: ExtHostConfiguration,
@IExtHostWorkspace private _extHostWorkspace: ExtHostWorkspace,
@IExtHostDocumentsAndEditors private _extHostDocumentsAndEditors: ExtHostDocumentsAndEditors,
@ILogService private _logService: ILogService
@IExtHostRpcService extHostRpc: IExtHostRpcService
) {
super(true, extHostRpc);

// Getting the SystemShell is an async operation, however, the ExtHost terminal service is mostly synchronous
// and the API `vscode.env.shell` is also synchronous. The default shell _should_ be set when extensions are
// starting up but if not, we run getSystemShellSync below which gets a sane default.
getSystemShell(platform.OS, process.env as platform.IProcessEnvironment).then(s => this._defaultShell = s);

this._updateLastActiveWorkspace();
this._registerListeners();
}

public createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal {
Expand Down Expand Up @@ -70,58 +42,4 @@ export class ExtHostTerminalService extends BaseExtHostTerminalService {
);
return terminal.value;
}

// TODO: Replace get shell/args calls with cached default shell given from renderer
public getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string {
return terminalEnvironment.getDefaultShell(
this._buildSafeConfigProvider(configProvider),
this._defaultShell ?? getSystemShellSync(platform.OS, process.env as platform.IProcessEnvironment),
process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432'),
process.env.windir,
terminalEnvironment.createVariableResolver(this._lastActiveWorkspace, process.env, this._variableResolver),
this._logService,
useAutomationShell
);
}

public getDefaultShellArgs(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string[] | string {
return terminalEnvironment.getDefaultShellArgs(
this._buildSafeConfigProvider(configProvider),
useAutomationShell,
terminalEnvironment.createVariableResolver(this._lastActiveWorkspace, process.env, this._variableResolver),
this._logService
);
}

private _registerListeners(): void {
this._extHostDocumentsAndEditors.onDidChangeActiveTextEditor(() => this._updateLastActiveWorkspace());
}

private _updateLastActiveWorkspace(): void {
const activeEditor = this._extHostDocumentsAndEditors.activeEditor();
if (activeEditor) {
this._lastActiveWorkspace = this._extHostWorkspace.getWorkspaceFolder(activeEditor.document.uri) as IWorkspaceFolder;
}
}

public async getDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto> {
const configProvider = await this._extHostConfiguration.getConfigProvider();
return {
shell: this.getDefaultShell(useAutomationShell, configProvider),
args: this.getDefaultShellArgs(useAutomationShell, configProvider)
};
}

// TODO: Remove when workspace trust is enabled
private _buildSafeConfigProvider(configProvider: ExtHostConfigProvider): SafeConfigProvider {
const config = configProvider.getConfiguration();
return (key: string) => {
const isWorkspaceConfigAllowed = config.get(TerminalSettingId.AllowWorkspaceConfiguration);
if (isWorkspaceConfigAllowed) {
return config.get(key) as any;
}
const inspected = config.inspect(key);
return inspected?.globalValue || inspected?.defaultValue;
};
}
}

0 comments on commit 6d70e72

Please sign in to comment.