Get default shell selector working
This commit is contained in:
parent
7dfbccb8e2
commit
c287c3cfc7
|
@ -28,6 +28,7 @@
|
|||
"yazl": "^2.4.3"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"vscode-windows-ca-certs": "0.1.0"
|
||||
"vscode-windows-ca-certs": "0.1.0",
|
||||
"vscode-windows-registry": "1.0.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1112,6 +1112,13 @@ vscode-windows-ca-certs@0.1.0:
|
|||
dependencies:
|
||||
node-addon-api "1.6.2"
|
||||
|
||||
vscode-windows-registry@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/vscode-windows-registry/-/vscode-windows-registry-1.0.1.tgz#bc9f765563eb6dc1c9ad9a41f9eaacc84dfadc7c"
|
||||
integrity sha512-q0aKXi9Py1OBdmXIJJFeJBzpPJMMUxMJNBU9FysWIXEwJyMQGEVevKzM2J3Qz/cHSc5LVqibmoUWzZ7g+97qRg==
|
||||
dependencies:
|
||||
nan "^2.12.1"
|
||||
|
||||
which-pm-runs@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb"
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY, IShellDefinition } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, ShellLaunchConfigDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { UriComponents, URI } from 'vs/base/common/uri';
|
||||
|
@ -22,11 +22,11 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
|||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@ITerminalService private readonly terminalService: ITerminalService
|
||||
@ITerminalService private readonly _terminalService: ITerminalService
|
||||
) {
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTerminalService);
|
||||
this._remoteAuthority = extHostContext.remoteAuthority;
|
||||
this._toDispose.push(terminalService.onInstanceCreated((instance) => {
|
||||
this._toDispose.push(_terminalService.onInstanceCreated((instance) => {
|
||||
// Delay this message so the TerminalInstance constructor has a chance to finish and
|
||||
// return the ID normally to the extension host. The ID that is passed here will be used
|
||||
// to register non-extension API terminals in the extension host.
|
||||
|
@ -35,25 +35,26 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
|||
this._onInstanceDimensionsChanged(instance);
|
||||
}, EXT_HOST_CREATION_DELAY);
|
||||
}));
|
||||
this._toDispose.push(terminalService.onInstanceDisposed(instance => this._onTerminalDisposed(instance)));
|
||||
this._toDispose.push(terminalService.onInstanceProcessIdReady(instance => this._onTerminalProcessIdReady(instance)));
|
||||
this._toDispose.push(terminalService.onInstanceDimensionsChanged(instance => this._onInstanceDimensionsChanged(instance)));
|
||||
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)));
|
||||
this._toDispose.push(_terminalService.onInstanceDisposed(instance => this._onTerminalDisposed(instance)));
|
||||
this._toDispose.push(_terminalService.onInstanceProcessIdReady(instance => this._onTerminalProcessIdReady(instance)));
|
||||
this._toDispose.push(_terminalService.onInstanceDimensionsChanged(instance => this._onInstanceDimensionsChanged(instance)));
|
||||
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)));
|
||||
this._toDispose.push(_terminalService.onRequestWindowsShells(r => this._onRequestDetectWindowsShell(r)));
|
||||
|
||||
// Set initial ext host state
|
||||
this.terminalService.terminalInstances.forEach(t => {
|
||||
this._terminalService.terminalInstances.forEach(t => {
|
||||
this._onTerminalOpened(t);
|
||||
t.processReady.then(() => this._onTerminalProcessIdReady(t));
|
||||
});
|
||||
const activeInstance = this.terminalService.getActiveInstance();
|
||||
const activeInstance = this._terminalService.getActiveInstance();
|
||||
if (activeInstance) {
|
||||
this._proxy.$acceptActiveTerminalChanged(activeInstance.id);
|
||||
}
|
||||
|
||||
this.terminalService.extHostReady(extHostContext.remoteAuthority);
|
||||
this._terminalService.extHostReady(extHostContext.remoteAuthority);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
|
@ -75,7 +76,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
|||
strictEnv,
|
||||
runInBackground
|
||||
};
|
||||
const terminal = this.terminalService.createTerminal(shellLaunchConfig);
|
||||
const terminal = this._terminalService.createTerminal(shellLaunchConfig);
|
||||
return Promise.resolve({
|
||||
id: terminal.id,
|
||||
name: terminal.title
|
||||
|
@ -83,55 +84,55 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
|||
}
|
||||
|
||||
public $createTerminalRenderer(name: string): Promise<number> {
|
||||
const instance = this.terminalService.createTerminalRenderer(name);
|
||||
const instance = this._terminalService.createTerminalRenderer(name);
|
||||
return Promise.resolve(instance.id);
|
||||
}
|
||||
|
||||
public $show(terminalId: number, preserveFocus: boolean): void {
|
||||
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
|
||||
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (terminalInstance) {
|
||||
this.terminalService.setActiveInstance(terminalInstance);
|
||||
this.terminalService.showPanel(!preserveFocus);
|
||||
this._terminalService.setActiveInstance(terminalInstance);
|
||||
this._terminalService.showPanel(!preserveFocus);
|
||||
}
|
||||
}
|
||||
|
||||
public $hide(terminalId: number): void {
|
||||
const instance = this.terminalService.getActiveInstance();
|
||||
const instance = this._terminalService.getActiveInstance();
|
||||
if (instance && instance.id === terminalId) {
|
||||
this.terminalService.hidePanel();
|
||||
this._terminalService.hidePanel();
|
||||
}
|
||||
}
|
||||
|
||||
public $dispose(terminalId: number): void {
|
||||
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
|
||||
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (terminalInstance) {
|
||||
terminalInstance.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public $terminalRendererWrite(terminalId: number, text: string): void {
|
||||
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
|
||||
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (terminalInstance && terminalInstance.shellLaunchConfig.isRendererOnly) {
|
||||
terminalInstance.write(text);
|
||||
}
|
||||
}
|
||||
|
||||
public $terminalRendererSetName(terminalId: number, name: string): void {
|
||||
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
|
||||
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (terminalInstance && terminalInstance.shellLaunchConfig.isRendererOnly) {
|
||||
terminalInstance.setTitle(name, false);
|
||||
}
|
||||
}
|
||||
|
||||
public $terminalRendererSetDimensions(terminalId: number, dimensions: ITerminalDimensions): void {
|
||||
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
|
||||
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (terminalInstance && terminalInstance.shellLaunchConfig.isRendererOnly) {
|
||||
terminalInstance.setDimensions(dimensions);
|
||||
}
|
||||
}
|
||||
|
||||
public $terminalRendererRegisterOnInputListener(terminalId: number): void {
|
||||
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
|
||||
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (!terminalInstance) {
|
||||
return;
|
||||
}
|
||||
|
@ -147,14 +148,14 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
|||
}
|
||||
|
||||
public $sendText(terminalId: number, text: string, addNewLine: boolean): void {
|
||||
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
|
||||
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (terminalInstance) {
|
||||
terminalInstance.sendText(text, addNewLine);
|
||||
}
|
||||
}
|
||||
|
||||
public $registerOnDataListener(terminalId: number): void {
|
||||
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
|
||||
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (!terminalInstance) {
|
||||
return;
|
||||
}
|
||||
|
@ -275,4 +276,8 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
|||
}
|
||||
this._terminalProcesses[terminalId].emitLatency(sum / COUNT);
|
||||
}
|
||||
|
||||
private _onRequestDetectWindowsShell(resolve: (shells: IShellDefinition[]) => void): void {
|
||||
this._proxy.$requestWindowsShells().then(shells => resolve(shells));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1106,6 +1106,11 @@ export interface ShellLaunchConfigDto {
|
|||
env?: { [key: string]: string | null };
|
||||
}
|
||||
|
||||
export interface IShellDefinitionDto {
|
||||
label: string;
|
||||
path: string;
|
||||
}
|
||||
|
||||
export interface ExtHostTerminalServiceShape {
|
||||
$acceptTerminalClosed(id: number): void;
|
||||
$acceptTerminalOpened(id: number, name: string): void;
|
||||
|
@ -1123,6 +1128,7 @@ export interface ExtHostTerminalServiceShape {
|
|||
$acceptProcessRequestCwd(id: number): void;
|
||||
$acceptProcessRequestLatency(id: number): number;
|
||||
$acceptWorkspacePermissionsChanged(isAllowed: boolean): void;
|
||||
$requestWindowsShells(): Promise<IShellDefinitionDto[]>;
|
||||
}
|
||||
|
||||
export interface ExtHostSCMShape {
|
||||
|
|
|
@ -10,7 +10,7 @@ import { URI, UriComponents } from 'vs/base/common/uri';
|
|||
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 { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IMainContext, ShellLaunchConfigDto, IShellDefinitionDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
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';
|
||||
|
@ -20,7 +20,7 @@ import { ExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
|||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { ExtHostVariableResolverService } from 'vs/workbench/api/node/extHostDebugService';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { getDefaultShell } from 'vs/workbench/contrib/terminal/node/terminal';
|
||||
import { getDefaultShell, detectWindowsShells } from 'vs/workbench/contrib/terminal/node/terminal';
|
||||
|
||||
const RENDERER_NO_PROCESS_ID = -1;
|
||||
|
||||
|
@ -575,6 +575,15 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
|||
return id;
|
||||
}
|
||||
|
||||
public $requestWindowsShells(): Promise<IShellDefinitionDto[]> {
|
||||
console.log('$requestWindowsShells');
|
||||
if (!platform.isWindows) {
|
||||
throw new Error('Can only detect Windows shells on Windows');
|
||||
}
|
||||
console.log('$requestWindowsShells2');
|
||||
return detectWindowsShells();
|
||||
}
|
||||
|
||||
private _onProcessExit(id: number, exitCode: number): void {
|
||||
// Remove listeners
|
||||
this._terminalProcesses[id].dispose();
|
||||
|
|
|
@ -370,10 +370,10 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ClearTerminalAct
|
|||
primary: 0,
|
||||
mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_K }
|
||||
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KeybindingWeight.WorkbenchContrib + 1), 'Terminal: Clear', category);
|
||||
// TODO: Web should support this as well, the shell query needs to go to the ext host though
|
||||
if (platform.isWindows && !platform.isWeb) {
|
||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectDefaultShellWindowsTerminalAction, SelectDefaultShellWindowsTerminalAction.ID, SelectDefaultShellWindowsTerminalAction.LABEL), 'Terminal: Select Default Shell', category);
|
||||
}
|
||||
// TODO: This should be the remote OS
|
||||
// if (platform.isWindows) {
|
||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectDefaultShellWindowsTerminalAction, SelectDefaultShellWindowsTerminalAction.ID, SelectDefaultShellWindowsTerminalAction.LABEL), 'Terminal: Select Default Shell', category);
|
||||
// }
|
||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(AllowWorkspaceShellTerminalCommand, AllowWorkspaceShellTerminalCommand.ID, AllowWorkspaceShellTerminalCommand.LABEL), 'Terminal: Allow Workspace Shell Configuration', category);
|
||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(DisallowWorkspaceShellTerminalCommand, DisallowWorkspaceShellTerminalCommand.ID, DisallowWorkspaceShellTerminalCommand.LABEL), 'Terminal: Disallow Workspace Shell Configuration', category);
|
||||
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(RenameTerminalAction, RenameTerminalAction.ID, RenameTerminalAction.LABEL), 'Terminal: Rename', category);
|
||||
|
|
|
@ -7,7 +7,7 @@ import * as nls from 'vs/nls';
|
|||
import { Action, IAction } from 'vs/base/common/actions';
|
||||
import { EndOfLinePreference } from 'vs/editor/common/model';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { ITerminalService, TERMINAL_PANEL_ID, ITerminalInstance, Direction, ITerminalConfigHelper, ITerminalNativeService } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ITerminalService, TERMINAL_PANEL_ID, ITerminalInstance, Direction, ITerminalConfigHelper } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { SelectActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { TogglePanelAction } from 'vs/workbench/browser/panel';
|
||||
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
|
@ -624,13 +624,13 @@ export class SelectDefaultShellWindowsTerminalAction extends Action {
|
|||
|
||||
constructor(
|
||||
id: string, label: string,
|
||||
@ITerminalNativeService private readonly _terminalNativeService: ITerminalNativeService
|
||||
@ITerminalService private readonly _terminalService: ITerminalService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
public run(event?: any): Promise<any> {
|
||||
return this._terminalNativeService.selectDefaultWindowsShell();
|
||||
return this._terminalService.selectDefaultWindowsShell();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -712,8 +712,7 @@ export class SwitchTerminalAction extends Action {
|
|||
|
||||
constructor(
|
||||
id: string, label: string,
|
||||
@ITerminalService private readonly terminalService: ITerminalService,
|
||||
@ITerminalNativeService private readonly terminalNativeService: ITerminalNativeService
|
||||
@ITerminalService private readonly terminalService: ITerminalService
|
||||
) {
|
||||
super(id, label, 'terminal-action switch-terminal');
|
||||
}
|
||||
|
@ -728,7 +727,7 @@ export class SwitchTerminalAction extends Action {
|
|||
}
|
||||
if (item === SelectDefaultShellWindowsTerminalAction.LABEL) {
|
||||
this.terminalService.refreshActiveTab();
|
||||
return this.terminalNativeService.selectDefaultWindowsShell();
|
||||
return this.terminalService.selectDefaultWindowsShell();
|
||||
}
|
||||
const selectedTabIndex = parseInt(item.split(':')[0], 10) - 1;
|
||||
this.terminalService.setActiveTabByIndex(selectedTabIndex);
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IOpenFileRequest } from 'vs/platform/windows/common/windows';
|
||||
import { ITerminalNativeService, LinuxDistro } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ITerminalNativeService, LinuxDistro, IShellDefinition } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
|
||||
export class TerminalNativeService implements ITerminalNativeService {
|
||||
|
@ -23,10 +23,6 @@ export class TerminalNativeService implements ITerminalNativeService {
|
|||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
public selectDefaultWindowsShell(): Promise<string | undefined> {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
public getWslPath(): Promise<string> {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
@ -34,4 +30,9 @@ export class TerminalNativeService implements ITerminalNativeService {
|
|||
public getWindowsBuildNumber(): number {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
// TODO: Remove local impl
|
||||
public detectWindowsShells(): Promise<IShellDefinition[]> {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
}
|
|
@ -21,6 +21,8 @@ import { TerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal
|
|||
import { IBrowserTerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper';
|
||||
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
|
||||
export class TerminalService extends CommonTerminalService implements ITerminalService {
|
||||
private _configHelper: IBrowserTerminalConfigHelper;
|
||||
|
@ -39,9 +41,11 @@ export class TerminalService extends CommonTerminalService implements ITerminalS
|
|||
@IExtensionService extensionService: IExtensionService,
|
||||
@IFileService fileService: IFileService,
|
||||
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
|
||||
@ITerminalNativeService readonly terminalNativeService: ITerminalNativeService
|
||||
@ITerminalNativeService readonly terminalNativeService: ITerminalNativeService,
|
||||
@IQuickInputService readonly quickInputService: IQuickInputService,
|
||||
@IConfigurationService readonly configurationService: IConfigurationService
|
||||
) {
|
||||
super(contextKeyService, panelService, lifecycleService, storageService, notificationService, dialogService, extensionService, fileService, remoteAgentService, terminalNativeService);
|
||||
super(contextKeyService, panelService, lifecycleService, storageService, notificationService, dialogService, extensionService, fileService, remoteAgentService, terminalNativeService, quickInputService, configurationService);
|
||||
this._configHelper = this._instantiationService.createInstance(TerminalConfigHelper, this.terminalNativeService.linuxDistro);
|
||||
}
|
||||
|
||||
|
|
|
@ -222,6 +222,7 @@ export interface ITerminalService {
|
|||
onInstancesChanged: Event<void>;
|
||||
onInstanceTitleChanged: Event<ITerminalInstance>;
|
||||
onActiveInstanceChanged: Event<ITerminalInstance | undefined>;
|
||||
onRequestWindowsShells: Event<(shells: IShellDefinition[]) => void>;
|
||||
|
||||
/**
|
||||
* Creates a terminal.
|
||||
|
@ -267,6 +268,8 @@ export interface ITerminalService {
|
|||
findNext(): void;
|
||||
findPrevious(): void;
|
||||
|
||||
selectDefaultWindowsShell(): Promise<void>;
|
||||
|
||||
setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void;
|
||||
setWorkspaceShellAllowed(isAllowed: boolean): void;
|
||||
|
||||
|
@ -299,7 +302,12 @@ export interface ITerminalNativeService {
|
|||
getWindowsBuildNumber(): number;
|
||||
whenFileDeleted(path: URI): Promise<void>;
|
||||
getWslPath(path: string): Promise<string>;
|
||||
selectDefaultWindowsShell(): Promise<string | undefined>;
|
||||
detectWindowsShells(): Promise<IShellDefinition[]>;
|
||||
}
|
||||
|
||||
export interface IShellDefinition {
|
||||
label: string;
|
||||
path: string;
|
||||
}
|
||||
|
||||
export const enum Direction {
|
||||
|
|
|
@ -8,7 +8,7 @@ import { Event, Emitter } from 'vs/base/common/event';
|
|||
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalConfigHelper, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, TERMINAL_PANEL_ID, ITerminalTab, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, ITerminalNativeService } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalConfigHelper, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, TERMINAL_PANEL_ID, ITerminalTab, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, ITerminalNativeService, IShellDefinition } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { FindReplaceState } from 'vs/editor/contrib/find/findState';
|
||||
|
@ -22,6 +22,8 @@ import { basename } from 'vs/base/common/path';
|
|||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { IOpenFileRequest } from 'vs/platform/windows/common/windows';
|
||||
import { IPickOptions, IQuickPickItem, IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
||||
|
||||
export abstract class TerminalService implements ITerminalService {
|
||||
public _serviceBrand: any;
|
||||
|
@ -63,6 +65,8 @@ export abstract class TerminalService implements ITerminalService {
|
|||
public get onActiveInstanceChanged(): Event<ITerminalInstance | undefined> { return this._onActiveInstanceChanged.event; }
|
||||
protected readonly _onTabDisposed = new Emitter<ITerminalTab>();
|
||||
public get onTabDisposed(): Event<ITerminalTab> { return this._onTabDisposed.event; }
|
||||
protected readonly _onRequestWindowsShells = new Emitter<(shells: IShellDefinition[]) => void>();
|
||||
public get onRequestWindowsShells(): Event<(shells: IShellDefinition[]) => void> { return this._onRequestWindowsShells.event; }
|
||||
|
||||
public abstract get configHelper(): ITerminalConfigHelper;
|
||||
|
||||
|
@ -76,7 +80,9 @@ export abstract class TerminalService implements ITerminalService {
|
|||
@IExtensionService private readonly _extensionService: IExtensionService,
|
||||
@IFileService protected readonly _fileService: IFileService,
|
||||
@IRemoteAgentService readonly _remoteAgentService: IRemoteAgentService,
|
||||
@ITerminalNativeService private readonly _terminalNativeService: ITerminalNativeService
|
||||
@ITerminalNativeService private readonly _terminalNativeService: ITerminalNativeService,
|
||||
@IQuickInputService private readonly _quickInputService: IQuickInputService,
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService
|
||||
) {
|
||||
this._activeTabIndex = 0;
|
||||
this._isShuttingDown = false;
|
||||
|
@ -522,4 +528,27 @@ export abstract class TerminalService implements ITerminalService {
|
|||
c(escapeNonWindowsPath(originalPath));
|
||||
});
|
||||
}
|
||||
|
||||
public selectDefaultWindowsShell(): Promise<void> {
|
||||
return this._detectWindowsShells().then(shells => {
|
||||
const options: IPickOptions<IQuickPickItem> = {
|
||||
placeHolder: nls.localize('terminal.integrated.chooseWindowsShell', "Select your preferred terminal shell, you can change this later in your settings")
|
||||
};
|
||||
const quickPickItems = shells.map(s => {
|
||||
return { label: s.label, description: s.path };
|
||||
});
|
||||
return this._quickInputService.pick(quickPickItems, options).then(async value => {
|
||||
if (!value) {
|
||||
return undefined;
|
||||
}
|
||||
const shell = value.description;
|
||||
await this._configurationService.updateValue('terminal.integrated.shell.windows', shell, ConfigurationTarget.USER).then(() => shell);
|
||||
return Promise.resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private _detectWindowsShells(): Promise<IShellDefinition[]> {
|
||||
return new Promise(r => this._onRequestWindowsShells.fire(r));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,19 +3,15 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import { ipcRenderer as ipc } from 'electron';
|
||||
import { IOpenFileRequest } from 'vs/platform/windows/common/windows';
|
||||
import { ITerminalNativeService, LinuxDistro } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ITerminalNativeService, LinuxDistro, IShellDefinition } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { getWindowsBuildNumber, linuxDistro } from 'vs/workbench/contrib/terminal/node/terminal';
|
||||
import { IQuickPickItem, IPickOptions, IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
|
||||
import { getWindowsBuildNumber, linuxDistro, detectWindowsShells } from 'vs/workbench/contrib/terminal/node/terminal';
|
||||
import { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
|
||||
import { execFile } from 'child_process';
|
||||
import { coalesce } from 'vs/base/common/arrays';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
|
||||
export class TerminalNativeService implements ITerminalNativeService {
|
||||
|
@ -30,8 +26,6 @@ export class TerminalNativeService implements ITerminalNativeService {
|
|||
|
||||
constructor(
|
||||
@IFileService private readonly _fileService: IFileService,
|
||||
@IQuickInputService private readonly _quickInputService: IQuickInputService,
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
@IInstantiationService readonly instantiationService: IInstantiationService,
|
||||
) {
|
||||
ipc.on('vscode:openFiles', (_event: any, request: IOpenFileRequest) => this._onOpenFileRequest.fire(request));
|
||||
|
@ -58,97 +52,8 @@ export class TerminalNativeService implements ITerminalNativeService {
|
|||
});
|
||||
}
|
||||
|
||||
public selectDefaultWindowsShell(): Promise<string | undefined> {
|
||||
return this._detectWindowsShells().then(shells => {
|
||||
const options: IPickOptions<IQuickPickItem> = {
|
||||
placeHolder: nls.localize('terminal.integrated.chooseWindowsShell', "Select your preferred terminal shell, you can change this later in your settings")
|
||||
};
|
||||
return this._quickInputService.pick(shells, options).then(value => {
|
||||
if (!value) {
|
||||
return undefined;
|
||||
}
|
||||
const shell = value.description;
|
||||
return this._configurationService.updateValue('terminal.integrated.shell.windows', shell, ConfigurationTarget.USER).then(() => shell);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the executable file path of shell from registry.
|
||||
* @param shellName The shell name to get the executable file path
|
||||
* @returns `[]` or `[ 'path' ]`
|
||||
*/
|
||||
private async _getShellPathFromRegistry(shellName: string): Promise<string[]> {
|
||||
const Registry = await import('vscode-windows-registry');
|
||||
|
||||
try {
|
||||
const shellPath = Registry.GetStringRegKey('HKEY_LOCAL_MACHINE', `SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\${shellName}.exe`, '');
|
||||
|
||||
if (shellPath === undefined) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [shellPath];
|
||||
} catch (error) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
private async _detectWindowsShells(): Promise<IQuickPickItem[]> {
|
||||
// Determine the correct System32 path. We want to point to Sysnative
|
||||
// when the 32-bit version of VS Code is running on a 64-bit machine.
|
||||
// The reason for this is because PowerShell's important PSReadline
|
||||
// module doesn't work if this is not the case. See #27915.
|
||||
const is32ProcessOn64Windows = process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432');
|
||||
const system32Path = `${process.env['windir']}\\${is32ProcessOn64Windows ? 'Sysnative' : 'System32'}`;
|
||||
|
||||
let useWSLexe = false;
|
||||
|
||||
if (getWindowsBuildNumber() >= 16299) {
|
||||
useWSLexe = true;
|
||||
}
|
||||
|
||||
const expectedLocations = {
|
||||
'Command Prompt': [`${system32Path}\\cmd.exe`],
|
||||
PowerShell: [`${system32Path}\\WindowsPowerShell\\v1.0\\powershell.exe`],
|
||||
'PowerShell Core': await this._getShellPathFromRegistry('pwsh'),
|
||||
'WSL Bash': [`${system32Path}\\${useWSLexe ? 'wsl.exe' : 'bash.exe'}`],
|
||||
'Git Bash': [
|
||||
`${process.env['ProgramW6432']}\\Git\\bin\\bash.exe`,
|
||||
`${process.env['ProgramW6432']}\\Git\\usr\\bin\\bash.exe`,
|
||||
`${process.env['ProgramFiles']}\\Git\\bin\\bash.exe`,
|
||||
`${process.env['ProgramFiles']}\\Git\\usr\\bin\\bash.exe`,
|
||||
`${process.env['LocalAppData']}\\Programs\\Git\\bin\\bash.exe`,
|
||||
]
|
||||
};
|
||||
const promises: PromiseLike<[string, string]>[] = [];
|
||||
Object.keys(expectedLocations).forEach(key => promises.push(this._validateShellPaths(key, expectedLocations[key])));
|
||||
return Promise.all(promises)
|
||||
.then(coalesce)
|
||||
.then(results => {
|
||||
return results.map(result => {
|
||||
return <IQuickPickItem>{
|
||||
label: result[0],
|
||||
description: result[1]
|
||||
};
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private _validateShellPaths(label: string, potentialPaths: string[]): Promise<[string, string] | null> {
|
||||
if (potentialPaths.length === 0) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
const current = potentialPaths.shift();
|
||||
if (current! === '') {
|
||||
return this._validateShellPaths(label, potentialPaths);
|
||||
}
|
||||
return this._fileService.exists(URI.file(current!)).then(exists => {
|
||||
if (!exists) {
|
||||
return this._validateShellPaths(label, potentialPaths);
|
||||
}
|
||||
return [label, current] as [string, string];
|
||||
});
|
||||
public detectWindowsShells(): Promise<IShellDefinition[]> {
|
||||
return detectWindowsShells();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,8 +6,10 @@
|
|||
import * as os from 'os';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import * as processes from 'vs/base/node/processes';
|
||||
import { readFile, fileExists } from 'vs/base/node/pfs';
|
||||
import { LinuxDistro } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { readFile, fileExists, stat } from 'vs/base/node/pfs';
|
||||
import { LinuxDistro, IShellDefinition } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { coalesce } from 'vs/base/common/arrays';
|
||||
import { normalize } from 'vs/base/common/path';
|
||||
|
||||
export function getDefaultShell(p: platform.Platform): string {
|
||||
if (p === platform.Platform.Windows) {
|
||||
|
@ -82,3 +84,68 @@ export function getWindowsBuildNumber(): number {
|
|||
}
|
||||
return buildNumber;
|
||||
}
|
||||
|
||||
export async function detectWindowsShells(): Promise<IShellDefinition[]> {
|
||||
console.log('a');
|
||||
// Determine the correct System32 path. We want to point to Sysnative
|
||||
// when the 32-bit version of VS Code is running on a 64-bit machine.
|
||||
// The reason for this is because PowerShell's important PSReadline
|
||||
// module doesn't work if this is not the case. See #27915.
|
||||
const is32ProcessOn64Windows = process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432');
|
||||
const system32Path = `${process.env['windir']}\\${is32ProcessOn64Windows ? 'Sysnative' : 'System32'}`;
|
||||
|
||||
let useWSLexe = false;
|
||||
|
||||
if (getWindowsBuildNumber() >= 16299) {
|
||||
useWSLexe = true;
|
||||
}
|
||||
|
||||
const expectedLocations = {
|
||||
'Command Prompt': [`${system32Path}\\cmd.exe`],
|
||||
PowerShell: [`${system32Path}\\WindowsPowerShell\\v1.0\\powershell.exe`],
|
||||
'PowerShell Core': [await getShellPathFromRegistry('pwsh')],
|
||||
'WSL Bash': [`${system32Path}\\${useWSLexe ? 'wsl.exe' : 'bash.exe'}`],
|
||||
'Git Bash': [
|
||||
`${process.env['ProgramW6432']}\\Git\\bin\\bash.exe`,
|
||||
`${process.env['ProgramW6432']}\\Git\\usr\\bin\\bash.exe`,
|
||||
`${process.env['ProgramFiles']}\\Git\\bin\\bash.exe`,
|
||||
`${process.env['ProgramFiles']}\\Git\\usr\\bin\\bash.exe`,
|
||||
`${process.env['LocalAppData']}\\Programs\\Git\\bin\\bash.exe`,
|
||||
]
|
||||
};
|
||||
const promises: PromiseLike<IShellDefinition | undefined>[] = [];
|
||||
Object.keys(expectedLocations).forEach(key => promises.push(validateShellPaths(key, expectedLocations[key])));
|
||||
|
||||
console.log('$detectWindowsShells');
|
||||
return Promise.all(promises).then(coalesce);
|
||||
}
|
||||
|
||||
|
||||
function validateShellPaths(label: string, potentialPaths: string[]): Promise<IShellDefinition | undefined> {
|
||||
if (potentialPaths.length === 0) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
const current = potentialPaths.shift()!;
|
||||
if (current! === '') {
|
||||
return validateShellPaths(label, potentialPaths);
|
||||
}
|
||||
return stat(normalize(current)).then(stat => {
|
||||
if (!stat.isFile && !stat.isSymbolicLink) {
|
||||
return validateShellPaths(label, potentialPaths);
|
||||
}
|
||||
return {
|
||||
label,
|
||||
path: current
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
async function getShellPathFromRegistry(shellName: string): Promise<string> {
|
||||
const Registry = await import('vscode-windows-registry');
|
||||
try {
|
||||
const shellPath = Registry.GetStringRegKey('HKEY_LOCAL_MACHINE', `SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\${shellName}.exe`, '');
|
||||
return shellPath ? shellPath : '';
|
||||
} catch (error) {
|
||||
return '';
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue