Skip to content

Commit

Permalink
Merge pull request #75455 from microsoft/tyriar/75091_default_shell_api
Browse files Browse the repository at this point in the history
Implement API to get default shell
  • Loading branch information
Tyriar committed Jun 14, 2019
2 parents 58be455 + 976320d commit 52a351f
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 14 deletions.
6 changes: 6 additions & 0 deletions src/vs/vscode.proposed.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1110,6 +1110,12 @@ declare module 'vscode' {
}

namespace window {
/**
* The detected default shell for the extension host, this is overridden by the
* `terminal.integrated.shell` setting for the extension host's platform.
*/
export const shell: string;

/**
* An event which fires when the [dimensions](#Terminal.dimensions) of the terminal change.
*/
Expand Down
5 changes: 5 additions & 0 deletions src/vs/workbench/api/browser/mainThreadTerminalService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
this._toDispose.push(terminalService.onInstanceRequestExtHostProcess(request => this._onTerminalRequestExtHostProcess(request)));
this._toDispose.push(terminalService.onActiveInstanceChanged(instance => this._onActiveTerminalChanged(instance ? instance.id : null)));
this._toDispose.push(terminalService.onInstanceTitleChanged(instance => this._onTitleChanged(instance.id, instance.title)));
this._toDispose.push(terminalService.configHelper.onWorkspacePermissionsChanged(isAllowed => this._onWorkspacePermissionsChanged(isAllowed)));

// Set initial ext host state
this.terminalService.terminalInstances.forEach(t => {
Expand Down Expand Up @@ -182,6 +183,10 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
this._proxy.$acceptTerminalTitleChange(terminalId, name);
}

private _onWorkspacePermissionsChanged(isAllowed: boolean): void {
this._proxy.$acceptWorkspacePermissionsChanged(isAllowed);
}

private _onTerminalRendererInput(terminalId: number, data: string): void {
this._proxy.$acceptTerminalRendererInput(terminalId, data);
}
Expand Down
1 change: 1 addition & 0 deletions src/vs/workbench/api/common/extHost.protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1122,6 +1122,7 @@ export interface ExtHostTerminalServiceShape {
$acceptProcessRequestInitialCwd(id: number): void;
$acceptProcessRequestCwd(id: number): void;
$acceptProcessRequestLatency(id: number): number;
$acceptWorkspacePermissionsChanged(isAllowed: boolean): void;
}

export interface ExtHostSCMShape {
Expand Down
3 changes: 3 additions & 0 deletions src/vs/workbench/api/node/extHost.api.impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,9 @@ export function createApiFactory(
get terminals() {
return extHostTerminalService.terminals;
},
get shell() {
return extHostTerminalService.getDefaultShell(configProvider);
},
showTextDocument(documentOrUri: vscode.TextDocument | vscode.Uri, columnOrOptions?: vscode.ViewColumn | vscode.TextDocumentShowOptions, preserveFocus?: boolean): Thenable<vscode.TextEditor> {
let documentPromise: Promise<vscode.TextDocument>;
if (URI.isUri(documentOrUri)) {
Expand Down
19 changes: 18 additions & 1 deletion src/vs/workbench/api/node/extHostTerminalService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import * as platform from 'vs/base/common/platform';
import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
import { Event, Emitter } from 'vs/base/common/event';
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IMainContext, ShellLaunchConfigDto } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
import { ExtHostConfiguration, ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
import { ILogService } from 'vs/platform/log/common/log';
import { EXT_HOST_CREATION_DELAY, IShellLaunchConfig, ITerminalEnvironment } from 'vs/workbench/contrib/terminal/common/terminal';
import { TerminalProcess } from 'vs/workbench/contrib/terminal/node/terminalProcess';
Expand Down Expand Up @@ -278,6 +278,9 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
private _terminalRenderers: ExtHostTerminalRenderer[] = [];
private _getTerminalPromises: { [id: number]: Promise<ExtHostTerminal> } = {};

// TODO: Pull this from main side
private _isWorkspaceShellAllowed: boolean = false;

public get activeTerminal(): ExtHostTerminal | undefined { return this._activeTerminal; }
public get terminals(): ExtHostTerminal[] { return this._terminals; }

Expand Down Expand Up @@ -325,6 +328,16 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
return renderer;
}

public getDefaultShell(configProvider: ExtHostConfigProvider): string {
const fetchSetting = (key: string) => {
const setting = configProvider
.getConfiguration(key.substr(0, key.lastIndexOf('.')))
.inspect<string | string[]>(key.substr(key.lastIndexOf('.') + 1));
return this._apiInspectConfigToPlain<string | string[]>(setting);
};
return terminalEnvironment.getDefaultShell(fetchSetting, this._isWorkspaceShellAllowed, getDefaultShell(platform.platform));
}

public async resolveTerminalRenderer(id: number): Promise<vscode.TerminalRenderer> {
// Check to see if the extension host already knows about this terminal.
for (const terminalRenderer of this._terminalRenderers) {
Expand Down Expand Up @@ -612,6 +625,10 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
});
return index;
}

public $acceptWorkspacePermissionsChanged(isAllowed: boolean): void {
this._isWorkspaceShellAllowed = isAllowed;
}
}

class ApiRequest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { Terminal as XTermTerminal } from 'xterm';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IBrowserTerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminal';
import { mergeDefaultShellPathAndArgs } from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
import { Emitter, Event } from 'vs/base/common/event';

const MINIMUM_FONT_SIZE = 6;
const MAXIMUM_FONT_SIZE = 25;
Expand All @@ -29,6 +30,9 @@ export class TerminalConfigHelper implements IBrowserTerminalConfigHelper {
private _lastFontMeasurement: ITerminalFont;
public config: ITerminalConfiguration;

private readonly _onWorkspacePermissionsChanged = new Emitter<boolean>();
public get onWorkspacePermissionsChanged(): Event<boolean> { return this._onWorkspacePermissionsChanged.event; }

public constructor(
private readonly _linuxDistro: LinuxDistro,
@IConfigurationService private readonly _configurationService: IConfigurationService,
Expand Down Expand Up @@ -160,6 +164,7 @@ export class TerminalConfigHelper implements IBrowserTerminalConfigHelper {
}

public setWorkspaceShellAllowed(isAllowed: boolean): void {
this._onWorkspacePermissionsChanged.fire(isAllowed);
this._storageService.store(IS_WORKSPACE_SHELL_ALLOWED_STORAGE_KEY, isAllowed, StorageScope.WORKSPACE);
}

Expand Down
8 changes: 6 additions & 2 deletions src/vs/workbench/contrib/terminal/common/terminal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ export interface ITerminalConfiguration {

export interface ITerminalConfigHelper {
config: ITerminalConfiguration;

onWorkspacePermissionsChanged: Event<boolean>;

configFontIsMonospace(): boolean;
getFont(): ITerminalFont;
/**
Expand Down Expand Up @@ -210,6 +213,9 @@ export interface ITerminalService {

activeTabIndex: number;
configHelper: ITerminalConfigHelper;
terminalInstances: ITerminalInstance[];
terminalTabs: ITerminalTab[];

onActiveTabChanged: Event<void>;
onTabDisposed: Event<ITerminalTab>;
onInstanceCreated: Event<ITerminalInstance>;
Expand All @@ -220,8 +226,6 @@ export interface ITerminalService {
onInstancesChanged: Event<void>;
onInstanceTitleChanged: Event<ITerminalInstance>;
onActiveInstanceChanged: Event<ITerminalInstance | undefined>;
terminalInstances: ITerminalInstance[];
terminalTabs: ITerminalTab[];

/**
* Creates a terminal.
Expand Down
43 changes: 32 additions & 11 deletions src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,34 +161,55 @@ export function escapeNonWindowsPath(path: string): string {
return newPath;
}

export function mergeDefaultShellPathAndArgs(
shell: IShellLaunchConfig,
export function getDefaultShell(
fetchSetting: (key: string) => { user: string | string[] | undefined, value: string | string[] | undefined, default: string | string[] | undefined },
isWorkspaceShellAllowed: boolean,
defaultShell: string,
platformOverride: platform.Platform = platform.platform
): void {
): string {
const platformKey = platformOverride === platform.Platform.Windows ? 'windows' : platformOverride === platform.Platform.Mac ? 'osx' : 'linux';
const shellConfigValue = fetchSetting(`terminal.integrated.shell.${platformKey}`);
const shellArgsConfigValue = fetchSetting(`terminal.integrated.shellArgs.${platformKey}`);

shell.executable = (isWorkspaceShellAllowed ? <string>shellConfigValue.value : <string>shellConfigValue.user) || (<string | null>shellConfigValue.default || defaultShell);
shell.args = (isWorkspaceShellAllowed ? <string[]>shellArgsConfigValue.value : <string[]>shellArgsConfigValue.user) || <string[]>shellArgsConfigValue.default;
let executable = (isWorkspaceShellAllowed ? <string>shellConfigValue.value : <string>shellConfigValue.user) || (<string | null>shellConfigValue.default || defaultShell);

// Change Sysnative to System32 if the OS is Windows but NOT WoW64. It's
// safe to assume that this was used by accident as Sysnative does not
// exist and will break the terminal in non-WoW64 environments.
if ((platformOverride === platform.Platform.Windows) && !process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432') && process.env.windir) {
const sysnativePath = path.join(process.env.windir, 'Sysnative').toLowerCase();
if (shell.executable && shell.executable.toLowerCase().indexOf(sysnativePath) === 0) {
shell.executable = path.join(process.env.windir, 'System32', shell.executable.substr(sysnativePath.length));
if (executable && executable.toLowerCase().indexOf(sysnativePath) === 0) {
executable = path.join(process.env.windir, 'System32', executable.substr(sysnativePath.length));
}
}

// Convert / to \ on Windows for convenience
if (shell.executable && platformOverride === platform.Platform.Windows) {
shell.executable = shell.executable.replace(/\//g, '\\');
if (executable && platformOverride === platform.Platform.Windows) {
executable = executable.replace(/\//g, '\\');
}

return executable;
}

function getDefaultShellArgs(
fetchSetting: (key: string) => { user: string | string[] | undefined, value: string | string[] | undefined, default: string | string[] | undefined },
isWorkspaceShellAllowed: boolean,
defaultShell: string,
platformOverride: platform.Platform = platform.platform
): string[] {
const platformKey = platformOverride === platform.Platform.Windows ? 'windows' : platformOverride === platform.Platform.Mac ? 'osx' : 'linux';
const shellArgsConfigValue = fetchSetting(`terminal.integrated.shellArgs.${platformKey}`);
const args = (isWorkspaceShellAllowed ? <string[]>shellArgsConfigValue.value : <string[]>shellArgsConfigValue.user) || <string[]>shellArgsConfigValue.default;
return args;
}

export function mergeDefaultShellPathAndArgs(
shell: IShellLaunchConfig,
fetchSetting: (key: string) => { user: string | string[] | undefined, value: string | string[] | undefined, default: string | string[] | undefined },
isWorkspaceShellAllowed: boolean,
defaultShell: string,
platformOverride: platform.Platform = platform.platform
): void {
shell.executable = getDefaultShell(fetchSetting, isWorkspaceShellAllowed, defaultShell, platformOverride);
shell.args = getDefaultShellArgs(fetchSetting, isWorkspaceShellAllowed, defaultShell, platformOverride);
}

export function createTerminalEnvironment(
Expand Down

0 comments on commit 52a351f

Please sign in to comment.