diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts index e5b7a74623f..6f463c6b13c 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/terminal.test.ts @@ -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); }); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts index 09a56a029be..450bb3d64d5 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstanceService.ts @@ -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()); + protected readonly _onRequestDefaultShellAndArgs = this._register(new Emitter()); readonly onRequestDefaultShellAndArgs = this._onRequestDefaultShellAndArgs.event; public async getXtermConstructor(): Promise { @@ -59,10 +53,6 @@ export class TerminalInstanceService extends Disposable implements ITerminalInst return WebglAddon; } - public createTerminalProcess(): Promise { - 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 { return {}; } - - getWorkspaceId(): string { - return ''; - } - setTerminalLayoutInfo(layout?: ITerminalsLayoutInfoById, id?: string): Promise { - throw new Error('Method not implemented.'); - } - getTerminalLayoutInfo(args?: IGetTerminalLayoutInfoArgs): Promise { - throw new Error('Method not implemented.'); - } - getTerminalLayouts(): Map { - return new Map(); - } - attachToProcess(id: number): Promise { - throw new Error('Method not implemented.'); - } } registerSingleton(ITerminalInstanceService, TerminalInstanceService, true); diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalNativeContribution.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalNativeContribution.ts index 18f764df2bc..3c7442aed9d 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalNativeContribution.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalNativeContribution.ts @@ -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 { - // 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 { - // Complete when wait marker file is deleted - return new Promise(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); - }); } /** diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/electron-sandbox/terminal.contribution.ts index 27bb3c730f9..03cd10397fb 100644 --- a/src/vs/workbench/contrib/terminal/electron-sandbox/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/electron-sandbox/terminal.contribution.ts @@ -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(WorkbenchExtensions.Workbench); +workbenchRegistry.registerWorkbenchContribution(TerminalNativeContribution, LifecyclePhase.Ready); diff --git a/src/vs/workbench/contrib/terminal/electron-sandbox/terminalNativeContribution.ts b/src/vs/workbench/contrib/terminal/electron-sandbox/terminalNativeContribution.ts new file mode 100644 index 00000000000..33267e38002 --- /dev/null +++ b/src/vs/workbench/contrib/terminal/electron-sandbox/terminalNativeContribution.ts @@ -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 { + // 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 { + // Complete when wait marker file is deleted + return new Promise(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); + }); + } +} diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts b/src/vs/workbench/contrib/terminal/electron-sandbox/terminalRemote.ts similarity index 80% rename from src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts rename to src/vs/workbench/contrib/terminal/electron-sandbox/terminalRemote.ts index 1547e863513..030ede3dd1d 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalRemote.ts +++ b/src/vs/workbench/contrib/terminal/electron-sandbox/terminalRemote.ts @@ -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(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 { - 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); } }