mirror of
https://github.com/microsoft/vscode.git
synced 2026-07-26 07:57:09 +01:00
Merge pull request #120002 from microsoft/tyriar/terminal_sandbox
electron-sandbox refactors for terminal
This commit is contained in:
@@ -23,7 +23,7 @@ import { assertNoRpc } from '../utils';
|
||||
// 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
|
||||
await config.update('gpuAcceleration', 'off', ConfigurationTarget.Global);
|
||||
await config.update('rendererType', 'off', ConfigurationTarget.Global);
|
||||
// Disable env var relaunch for tests to prevent terminals relaunching themselves
|
||||
await config.update('environmentChangesRelaunch', false, ConfigurationTarget.Global);
|
||||
});
|
||||
|
||||
@@ -10,11 +10,9 @@ import type { SearchAddon as XTermSearchAddon } from 'xterm-addon-search';
|
||||
import type { Unicode11Addon as XTermUnicode11Addon } from 'xterm-addon-unicode11';
|
||||
import type { WebglAddon as XTermWebglAddon } from 'xterm-addon-webgl';
|
||||
import { IProcessEnvironment } from 'vs/base/common/platform';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ITerminalsLayoutInfoById, ITerminalsLayoutInfo, ITerminalChildProcess } from 'vs/platform/terminal/common/terminal';
|
||||
import { IGetTerminalLayoutInfoArgs } from 'vs/platform/terminal/common/terminalProcess';
|
||||
|
||||
let Terminal: typeof XTermTerminal;
|
||||
let SearchAddon: typeof XTermSearchAddon;
|
||||
@@ -24,11 +22,7 @@ let WebglAddon: typeof XTermWebglAddon;
|
||||
export class TerminalInstanceService extends Disposable implements ITerminalInstanceService {
|
||||
public _serviceBrand: undefined;
|
||||
|
||||
readonly onPtyHostExit = Event.None;
|
||||
readonly onPtyHostUnresponsive = Event.None;
|
||||
readonly onPtyHostResponsive = Event.None;
|
||||
readonly onPtyHostRestart = Event.None;
|
||||
private readonly _onRequestDefaultShellAndArgs = this._register(new Emitter<IDefaultShellAndArgsRequest>());
|
||||
protected readonly _onRequestDefaultShellAndArgs = this._register(new Emitter<IDefaultShellAndArgsRequest>());
|
||||
readonly onRequestDefaultShellAndArgs = this._onRequestDefaultShellAndArgs.event;
|
||||
|
||||
public async getXtermConstructor(): Promise<typeof XTermTerminal> {
|
||||
@@ -59,10 +53,6 @@ export class TerminalInstanceService extends Disposable implements ITerminalInst
|
||||
return WebglAddon;
|
||||
}
|
||||
|
||||
public createTerminalProcess(): Promise<ITerminalChildProcess> {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
public getDefaultShellAndArgs(useAutomationShell: boolean,): Promise<{ shell: string, args: string[] | string | undefined }> {
|
||||
return new Promise(r => this._onRequestDefaultShellAndArgs.fire({
|
||||
useAutomationShell,
|
||||
@@ -73,22 +63,6 @@ export class TerminalInstanceService extends Disposable implements ITerminalInst
|
||||
public async getMainProcessParentEnv(): Promise<IProcessEnvironment> {
|
||||
return {};
|
||||
}
|
||||
|
||||
getWorkspaceId(): string {
|
||||
return '';
|
||||
}
|
||||
setTerminalLayoutInfo(layout?: ITerminalsLayoutInfoById, id?: string): Promise<void> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
getTerminalLayoutInfo(args?: IGetTerminalLayoutInfoArgs): Promise<ITerminalsLayoutInfo | undefined> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
getTerminalLayouts(): Map<string, ITerminalsLayoutInfo> {
|
||||
return new Map<string, ITerminalsLayoutInfo>();
|
||||
}
|
||||
attachToProcess(id: number): Promise<ITerminalChildProcess> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(ITerminalInstanceService, TerminalInstanceService, true);
|
||||
|
||||
@@ -3,14 +3,9 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ipcRenderer } from 'vs/base/parts/sandbox/electron-sandbox/globals';
|
||||
import { INativeOpenFileRequest } from 'vs/platform/windows/common/windows';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
|
||||
import { execFile } from 'child_process';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { registerRemoteContributions } from 'vs/workbench/contrib/terminal/electron-browser/terminalRemote';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { INativeHostService } from 'vs/platform/native/electron-sandbox/native';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
@@ -23,7 +18,6 @@ export class TerminalNativeContribution extends Disposable implements IWorkbench
|
||||
public _serviceBrand: undefined;
|
||||
|
||||
constructor(
|
||||
@IFileService private readonly _fileService: IFileService,
|
||||
@ITerminalService private readonly _terminalService: ITerminalService,
|
||||
@IInstantiationService readonly instantiationService: IInstantiationService,
|
||||
@IRemoteAgentService readonly remoteAgentService: IRemoteAgentService,
|
||||
@@ -31,55 +25,11 @@ export class TerminalNativeContribution extends Disposable implements IWorkbench
|
||||
) {
|
||||
super();
|
||||
|
||||
ipcRenderer.on('vscode:openFiles', (_: unknown, request: INativeOpenFileRequest) => this._onOpenFileRequest(request));
|
||||
this._register(nativeHostService.onDidResumeOS(() => this._onOsResume()));
|
||||
|
||||
this._terminalService.setLinuxDistro(linuxDistro);
|
||||
this._terminalService.setNativeWindowsDelegate({
|
||||
getWslPath: this._getWslPath.bind(this),
|
||||
getWindowsBuildNumber: this._getWindowsBuildNumber.bind(this)
|
||||
});
|
||||
|
||||
const connection = remoteAgentService.getConnection();
|
||||
if (connection && connection.remoteAuthority) {
|
||||
registerRemoteContributions();
|
||||
}
|
||||
}
|
||||
|
||||
private _onOsResume(): void {
|
||||
this._terminalService.terminalInstances.forEach(instance => instance.forceRedraw());
|
||||
}
|
||||
|
||||
private async _onOpenFileRequest(request: INativeOpenFileRequest): Promise<void> {
|
||||
// if the request to open files is coming in from the integrated terminal (identified though
|
||||
// the termProgram variable) and we are instructed to wait for editors close, wait for the
|
||||
// marker file to get deleted and then focus back to the integrated terminal.
|
||||
if (request.termProgram === 'vscode' && request.filesToWait) {
|
||||
const waitMarkerFileUri = URI.revive(request.filesToWait.waitMarkerFileUri);
|
||||
await this._whenFileDeleted(waitMarkerFileUri);
|
||||
|
||||
// Focus active terminal
|
||||
this._terminalService.getActiveInstance()?.focus();
|
||||
}
|
||||
}
|
||||
|
||||
private _whenFileDeleted(path: URI): Promise<void> {
|
||||
// Complete when wait marker file is deleted
|
||||
return new Promise<void>(resolve => {
|
||||
let running = false;
|
||||
const interval = setInterval(async () => {
|
||||
if (!running) {
|
||||
running = true;
|
||||
const exists = await this._fileService.exists(path);
|
||||
running = false;
|
||||
|
||||
if (!exists) {
|
||||
clearInterval(interval);
|
||||
resolve(undefined);
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,10 +5,17 @@
|
||||
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { registerSharedProcessRemoteService } from 'vs/platform/ipc/electron-sandbox/services';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { ILocalTerminalService, TerminalIpcChannels } from 'vs/platform/terminal/common/terminal';
|
||||
import { ILocalPtyService } from 'vs/platform/terminal/electron-sandbox/terminal';
|
||||
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
|
||||
import { LocalTerminalService } from 'vs/workbench/contrib/terminal/electron-sandbox/localTerminalService';
|
||||
import { TerminalNativeContribution } from 'vs/workbench/contrib/terminal/electron-sandbox/terminalNativeContribution';
|
||||
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||
|
||||
registerSharedProcessRemoteService(ILocalPtyService, TerminalIpcChannels.LocalPty, { supportsDelayedInstantiation: true });
|
||||
|
||||
registerSingleton(ILocalTerminalService, LocalTerminalService, true);
|
||||
|
||||
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
|
||||
workbenchRegistry.registerWorkbenchContribution(TerminalNativeContribution, LifecyclePhase.Ready);
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ipcRenderer } from 'vs/base/parts/sandbox/electron-sandbox/globals';
|
||||
import { INativeOpenFileRequest } from 'vs/platform/windows/common/windows';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { registerRemoteContributions } from 'vs/workbench/contrib/terminal/electron-sandbox/terminalRemote';
|
||||
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
|
||||
import { INativeHostService } from 'vs/platform/native/electron-sandbox/native';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
|
||||
export class TerminalNativeContribution extends Disposable implements IWorkbenchContribution {
|
||||
public _serviceBrand: undefined;
|
||||
|
||||
constructor(
|
||||
@IFileService private readonly _fileService: IFileService,
|
||||
@ITerminalService private readonly _terminalService: ITerminalService,
|
||||
@IInstantiationService readonly instantiationService: IInstantiationService,
|
||||
@IRemoteAgentService readonly remoteAgentService: IRemoteAgentService,
|
||||
@INativeHostService readonly nativeHostService: INativeHostService
|
||||
) {
|
||||
super();
|
||||
|
||||
ipcRenderer.on('vscode:openFiles', (_: unknown, request: INativeOpenFileRequest) => this._onOpenFileRequest(request));
|
||||
this._register(nativeHostService.onDidResumeOS(() => this._onOsResume()));
|
||||
|
||||
const connection = remoteAgentService.getConnection();
|
||||
if (connection && connection.remoteAuthority) {
|
||||
registerRemoteContributions();
|
||||
}
|
||||
}
|
||||
|
||||
private _onOsResume(): void {
|
||||
this._terminalService.terminalInstances.forEach(instance => instance.forceRedraw());
|
||||
}
|
||||
|
||||
private async _onOpenFileRequest(request: INativeOpenFileRequest): Promise<void> {
|
||||
// if the request to open files is coming in from the integrated terminal (identified though
|
||||
// the termProgram variable) and we are instructed to wait for editors close, wait for the
|
||||
// marker file to get deleted and then focus back to the integrated terminal.
|
||||
if (request.termProgram === 'vscode' && request.filesToWait) {
|
||||
const waitMarkerFileUri = URI.revive(request.filesToWait.waitMarkerFileUri);
|
||||
await this._whenFileDeleted(waitMarkerFileUri);
|
||||
|
||||
// Focus active terminal
|
||||
this._terminalService.getActiveInstance()?.focus();
|
||||
}
|
||||
}
|
||||
|
||||
private _whenFileDeleted(path: URI): Promise<void> {
|
||||
// Complete when wait marker file is deleted
|
||||
return new Promise<void>(resolve => {
|
||||
let running = false;
|
||||
const interval = setInterval(async () => {
|
||||
if (!running) {
|
||||
running = true;
|
||||
const exists = await this._fileService.exists(path);
|
||||
running = false;
|
||||
|
||||
if (!exists) {
|
||||
clearInterval(interval);
|
||||
resolve(undefined);
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
}
|
||||
+6
-6
@@ -9,9 +9,8 @@ import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/wor
|
||||
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
|
||||
import { TERMINAL_ACTION_CATEGORY, TitleEventSource, TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { homedir } from 'os';
|
||||
import { ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
|
||||
import { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
|
||||
export function registerRemoteContributions() {
|
||||
const actionRegistry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
|
||||
@@ -24,13 +23,14 @@ export class CreateNewLocalTerminalAction extends Action {
|
||||
|
||||
constructor(
|
||||
id: string, label: string,
|
||||
@ITerminalService private readonly terminalService: ITerminalService
|
||||
@ITerminalService private readonly _terminalService: ITerminalService,
|
||||
@INativeEnvironmentService private readonly _nativeEnvironmentService: INativeEnvironmentService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
public run(): Promise<any> {
|
||||
const instance = this.terminalService.createTerminal({ cwd: URI.file(homedir()) });
|
||||
const instance = this._terminalService.createTerminal({ cwd: this._nativeEnvironmentService.userHome });
|
||||
if (!instance) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
@@ -43,7 +43,7 @@ export class CreateNewLocalTerminalAction extends Action {
|
||||
}
|
||||
});
|
||||
|
||||
this.terminalService.setActiveInstance(instance);
|
||||
return this.terminalService.showPanel(true);
|
||||
this._terminalService.setActiveInstance(instance);
|
||||
return this._terminalService.showPanel(true);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user