mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-25 19:18:59 +01:00
Merge remote-tracking branch 'origin/main' into pr/habibkarim/115276
This commit is contained in:
@@ -5,22 +5,23 @@
|
||||
|
||||
import type * as vscode from 'vscode';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto, ITerminalDimensionsDto, ITerminalLinkDto, TerminalIdentifier } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IShellAndArgsDto, ITerminalDimensionsDto, ITerminalLinkDto, TerminalIdentifier } 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, UriComponents } from 'vs/base/common/uri';
|
||||
import { ITerminalChildProcess, ITerminalLaunchError, ITerminalDimensionsOverride } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
import { TerminalDataBufferer } from 'vs/workbench/contrib/terminal/common/terminalDataBuffering';
|
||||
import { IDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { Disposable as VSCodeDisposable, EnvironmentVariableMutatorType } from './extHostTypes';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
|
||||
import { localize } from 'vs/nls';
|
||||
import { NotSupportedError } from 'vs/base/common/errors';
|
||||
import { serializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
|
||||
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 { TerminalDataBufferer } from 'vs/platform/terminal/common/terminalDataBuffering';
|
||||
import { ITerminalProfile } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
|
||||
export interface IExtHostTerminalService extends ExtHostTerminalServiceShape, IDisposable {
|
||||
|
||||
@@ -47,7 +48,7 @@ export interface IExtHostTerminalService extends ExtHostTerminalServiceShape, ID
|
||||
|
||||
export const IExtHostTerminalService = createDecorator<IExtHostTerminalService>('IExtHostTerminalService');
|
||||
|
||||
export class ExtHostTerminal implements vscode.Terminal {
|
||||
export class ExtHostTerminal {
|
||||
private _disposed: boolean = false;
|
||||
private _pidPromise: Promise<number | undefined>;
|
||||
private _cols: number | undefined;
|
||||
@@ -57,6 +58,8 @@ export class ExtHostTerminal implements vscode.Terminal {
|
||||
|
||||
public isOpen: boolean = false;
|
||||
|
||||
readonly value: vscode.Terminal;
|
||||
|
||||
constructor(
|
||||
private _proxy: MainThreadTerminalServiceShape,
|
||||
public _id: TerminalIdentifier,
|
||||
@@ -65,29 +68,73 @@ export class ExtHostTerminal implements vscode.Terminal {
|
||||
) {
|
||||
this._creationOptions = Object.freeze(this._creationOptions);
|
||||
this._pidPromise = new Promise<number | undefined>(c => this._pidPromiseComplete = c);
|
||||
|
||||
const that = this;
|
||||
this.value = {
|
||||
get name(): string {
|
||||
return that._name || '';
|
||||
},
|
||||
get processId(): Promise<number | undefined> {
|
||||
return that._pidPromise;
|
||||
},
|
||||
get creationOptions(): Readonly<vscode.TerminalOptions | vscode.ExtensionTerminalOptions> {
|
||||
return that._creationOptions;
|
||||
},
|
||||
get exitStatus(): vscode.TerminalExitStatus | undefined {
|
||||
return that._exitStatus;
|
||||
},
|
||||
sendText(text: string, addNewLine: boolean = true): void {
|
||||
that._checkDisposed();
|
||||
that._proxy.$sendText(that._id, text, addNewLine);
|
||||
},
|
||||
show(preserveFocus: boolean): void {
|
||||
that._checkDisposed();
|
||||
that._proxy.$show(that._id, preserveFocus);
|
||||
},
|
||||
hide(): void {
|
||||
that._checkDisposed();
|
||||
that._proxy.$hide(that._id);
|
||||
},
|
||||
dispose(): void {
|
||||
if (!that._disposed) {
|
||||
that._disposed = true;
|
||||
that._proxy.$dispose(that._id);
|
||||
}
|
||||
},
|
||||
get dimensions(): vscode.TerminalDimensions | undefined {
|
||||
if (that._cols === undefined || that._rows === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
columns: that._cols,
|
||||
rows: that._rows
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public async create(
|
||||
shellPath?: string,
|
||||
shellArgs?: string[] | string,
|
||||
cwd?: string | URI,
|
||||
env?: { [key: string]: string | null },
|
||||
env?: ITerminalEnvironment,
|
||||
waitOnExit?: boolean,
|
||||
strictEnv?: boolean,
|
||||
hideFromUser?: boolean,
|
||||
isFeatureTerminal?: boolean
|
||||
isFeatureTerminal?: boolean,
|
||||
isExtensionOwnedTerminal?: boolean
|
||||
): Promise<void> {
|
||||
if (typeof this._id !== 'string') {
|
||||
throw new Error('Terminal has already been created');
|
||||
}
|
||||
await this._proxy.$createTerminal(this._id, { name: this._name, shellPath, shellArgs, cwd, env, waitOnExit, strictEnv, hideFromUser, isFeatureTerminal });
|
||||
await this._proxy.$createTerminal(this._id, { name: this._name, shellPath, shellArgs, cwd, env, waitOnExit, strictEnv, hideFromUser, isFeatureTerminal, isExtensionOwnedTerminal });
|
||||
}
|
||||
|
||||
public async createExtensionTerminal(): Promise<number> {
|
||||
if (typeof this._id !== 'string') {
|
||||
throw new Error('Terminal has already been created');
|
||||
}
|
||||
await this._proxy.$createTerminal(this._id, { name: this._name, isExtensionTerminal: true });
|
||||
await this._proxy.$createTerminal(this._id, { name: this._name, isExtensionCustomPtyTerminal: true });
|
||||
// At this point, the id has been set via `$acceptTerminalOpened`
|
||||
if (typeof this._id === 'string') {
|
||||
throw new Error('Terminal creation failed');
|
||||
@@ -95,41 +142,16 @@ export class ExtHostTerminal implements vscode.Terminal {
|
||||
return this._id;
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
if (!this._disposed) {
|
||||
this._disposed = true;
|
||||
this._proxy.$dispose(this._id);
|
||||
}
|
||||
}
|
||||
|
||||
private _checkDisposed() {
|
||||
if (this._disposed) {
|
||||
throw new Error('Terminal has already been disposed');
|
||||
}
|
||||
}
|
||||
|
||||
public get name(): string {
|
||||
return this._name || '';
|
||||
}
|
||||
|
||||
public set name(name: string) {
|
||||
this._name = name;
|
||||
}
|
||||
|
||||
public get exitStatus(): vscode.TerminalExitStatus | undefined {
|
||||
return this._exitStatus;
|
||||
}
|
||||
|
||||
public get dimensions(): vscode.TerminalDimensions | undefined {
|
||||
if (this._cols === undefined || this._rows === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
columns: this._cols,
|
||||
rows: this._rows
|
||||
};
|
||||
}
|
||||
|
||||
public setExitCode(code: number | undefined) {
|
||||
this._exitStatus = Object.freeze({ code });
|
||||
}
|
||||
@@ -147,29 +169,6 @@ export class ExtHostTerminal implements vscode.Terminal {
|
||||
return true;
|
||||
}
|
||||
|
||||
public get processId(): Promise<number | undefined> {
|
||||
return this._pidPromise;
|
||||
}
|
||||
|
||||
public get creationOptions(): Readonly<vscode.TerminalOptions | vscode.ExtensionTerminalOptions> {
|
||||
return this._creationOptions;
|
||||
}
|
||||
|
||||
public sendText(text: string, addNewLine: boolean = true): void {
|
||||
this._checkDisposed();
|
||||
this._proxy.$sendText(this._id, text, addNewLine);
|
||||
}
|
||||
|
||||
public show(preserveFocus: boolean): void {
|
||||
this._checkDisposed();
|
||||
this._proxy.$show(this._id, preserveFocus);
|
||||
}
|
||||
|
||||
public hide(): void {
|
||||
this._checkDisposed();
|
||||
this._proxy.$hide(this._id);
|
||||
}
|
||||
|
||||
public _setProcessId(processId: number | undefined): void {
|
||||
// The event may fire 2 times when the panel is restored
|
||||
if (this._pidPromiseComplete) {
|
||||
@@ -187,6 +186,9 @@ export class ExtHostTerminal implements vscode.Terminal {
|
||||
}
|
||||
|
||||
export class ExtHostPseudoterminal implements ITerminalChildProcess {
|
||||
readonly id = 0;
|
||||
readonly shouldPersist = false;
|
||||
|
||||
private readonly _onProcessData = new Emitter<string>();
|
||||
public readonly onProcessData: Event<string> = this._onProcessData.event;
|
||||
private readonly _onProcessExit = new Emitter<number | undefined>();
|
||||
@@ -197,6 +199,9 @@ export class ExtHostPseudoterminal implements ITerminalChildProcess {
|
||||
public readonly onProcessTitleChanged: Event<string> = this._onProcessTitleChanged.event;
|
||||
private readonly _onProcessOverrideDimensions = new Emitter<ITerminalDimensionsOverride | undefined>();
|
||||
public get onProcessOverrideDimensions(): Event<ITerminalDimensionsOverride | undefined> { return this._onProcessOverrideDimensions.event; }
|
||||
private readonly _onProcessShellTypeChanged = new Emitter<TerminalShellType>();
|
||||
public readonly onProcessShellTypeChanged = this._onProcessShellTypeChanged.event;
|
||||
|
||||
|
||||
constructor(private readonly _pty: vscode.Pseudoterminal) { }
|
||||
|
||||
@@ -220,6 +225,10 @@ export class ExtHostPseudoterminal implements ITerminalChildProcess {
|
||||
}
|
||||
}
|
||||
|
||||
processBinary(data: string) {
|
||||
throw new Error('not implemented');
|
||||
}
|
||||
|
||||
acknowledgeDataEvent(charCount: number): void {
|
||||
// No-op, flow control is not supported in extension owned terminals. If this is ever
|
||||
// implemented it will need new pause and resume VS Code APIs.
|
||||
@@ -287,8 +296,8 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
|
||||
private readonly _terminalLinkCache: Map<number, Map<number, ICachedLinkEntry>> = new Map();
|
||||
private readonly _terminalLinkCancellationSource: Map<number, CancellationTokenSource> = new Map();
|
||||
|
||||
public get activeTerminal(): ExtHostTerminal | undefined { return this._activeTerminal; }
|
||||
public get terminals(): ExtHostTerminal[] { return this._terminals; }
|
||||
public get activeTerminal(): vscode.Terminal | undefined { return this._activeTerminal?.value; }
|
||||
public get terminals(): vscode.Terminal[] { return this._terminals.map(term => term.value); }
|
||||
|
||||
protected readonly _onDidCloseTerminal: Emitter<vscode.Terminal> = new Emitter<vscode.Terminal>();
|
||||
public get onDidCloseTerminal(): Event<vscode.Terminal> { return this._onDidCloseTerminal && this._onDidCloseTerminal.event; }
|
||||
@@ -326,8 +335,7 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
|
||||
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 $spawnExtHostProcess(id: number, shellLaunchConfigDto: IShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise<ITerminalLaunchError | undefined>;
|
||||
public abstract $getAvailableShells(): Promise<IShellDefinitionDto[]>;
|
||||
public abstract $getAvailableProfiles(configuredProfilesOnly: boolean): Promise<ITerminalProfile[]>;
|
||||
public abstract $getDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto>;
|
||||
public abstract $acceptWorkspacePermissionsChanged(isAllowed: boolean): void;
|
||||
|
||||
@@ -339,7 +347,7 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
|
||||
this._terminalProcessDisposables[id] = disposable;
|
||||
});
|
||||
this._terminals.push(terminal);
|
||||
return terminal;
|
||||
return terminal.value;
|
||||
}
|
||||
|
||||
public attachPtyToTerminal(id: number, pty: vscode.Pseudoterminal): void {
|
||||
@@ -365,7 +373,7 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
|
||||
if (terminal) {
|
||||
this._activeTerminal = terminal;
|
||||
if (original !== this._activeTerminal) {
|
||||
this._onDidChangeActiveTerminal.fire(this._activeTerminal);
|
||||
this._onDidChangeActiveTerminal.fire(this._activeTerminal.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -373,7 +381,7 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
|
||||
public async $acceptTerminalProcessData(id: number, data: string): Promise<void> {
|
||||
const terminal = this._getTerminalById(id);
|
||||
if (terminal) {
|
||||
this._onDidWriteTerminalData.fire({ terminal, data });
|
||||
this._onDidWriteTerminalData.fire({ terminal: terminal.value, data });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,8 +390,8 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
|
||||
if (terminal) {
|
||||
if (terminal.setDimensions(cols, rows)) {
|
||||
this._onDidChangeTerminalDimensions.fire({
|
||||
terminal: terminal,
|
||||
dimensions: terminal.dimensions as vscode.TerminalDimensions
|
||||
terminal: terminal.value,
|
||||
dimensions: terminal.value.dimensions as vscode.TerminalDimensions
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -403,11 +411,11 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
|
||||
}
|
||||
|
||||
public async $acceptTerminalClosed(id: number, exitCode: number | undefined): Promise<void> {
|
||||
const index = this._getTerminalObjectIndexById(this.terminals, id);
|
||||
const index = this._getTerminalObjectIndexById(this._terminals, id);
|
||||
if (index !== null) {
|
||||
const terminal = this._terminals.splice(index, 1)[0];
|
||||
terminal.setExitCode(exitCode);
|
||||
this._onDidCloseTerminal.fire(terminal);
|
||||
this._onDidCloseTerminal.fire(terminal.value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,9 +425,9 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
|
||||
const index = this._getTerminalObjectIndexById(this._terminals, extHostTerminalId);
|
||||
if (index !== null) {
|
||||
// The terminal has already been created (via createTerminal*), only fire the event
|
||||
this.terminals[index]._id = id;
|
||||
this._terminals[index]._id = id;
|
||||
this._onDidOpenTerminal.fire(this.terminals[index]);
|
||||
this.terminals[index].isOpen = true;
|
||||
this._terminals[index].isOpen = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -434,7 +442,7 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
|
||||
};
|
||||
const terminal = new ExtHostTerminal(this._proxy, id, creationOptions, name);
|
||||
this._terminals.push(terminal);
|
||||
this._onDidOpenTerminal.fire(terminal);
|
||||
this._onDidOpenTerminal.fire(terminal.value);
|
||||
terminal.isOpen = true;
|
||||
}
|
||||
|
||||
@@ -458,7 +466,7 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
|
||||
await new Promise<void>(r => {
|
||||
// Ensure open is called after onDidOpenTerminal
|
||||
const listener = this.onDidOpenTerminal(async e => {
|
||||
if (e === terminal) {
|
||||
if (e === terminal.value) {
|
||||
listener.dispose();
|
||||
r();
|
||||
}
|
||||
@@ -567,7 +575,7 @@ export abstract class BaseExtHostTerminalService extends Disposable implements I
|
||||
this._terminalLinkCancellationSource.set(terminalId, cancellationSource);
|
||||
|
||||
const result: ITerminalLinkDto[] = [];
|
||||
const context: vscode.TerminalLinkContext = { terminal, line };
|
||||
const context: vscode.TerminalLinkContext = { terminal: terminal.value, line };
|
||||
const promises: vscode.ProviderResult<{ provider: vscode.TerminalLinkProvider, links: vscode.TerminalLink[] }>[] = [];
|
||||
|
||||
for (const provider of this._linkProviders) {
|
||||
@@ -770,19 +778,14 @@ export class WorkerExtHostTerminalService extends BaseExtHostTerminalService {
|
||||
}
|
||||
|
||||
public getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string {
|
||||
// Return the empty string to avoid throwing
|
||||
return '';
|
||||
throw new NotSupportedError();
|
||||
}
|
||||
|
||||
public getDefaultShellArgs(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string[] | string {
|
||||
throw new NotSupportedError();
|
||||
}
|
||||
|
||||
public $spawnExtHostProcess(id: number, shellLaunchConfigDto: IShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise<ITerminalLaunchError | undefined> {
|
||||
throw new NotSupportedError();
|
||||
}
|
||||
|
||||
public $getAvailableShells(): Promise<IShellDefinitionDto[]> {
|
||||
public $getAvailableProfiles(configuredProfilesOnly: boolean): Promise<ITerminalProfile[]> {
|
||||
throw new NotSupportedError();
|
||||
}
|
||||
|
||||
@@ -791,6 +794,6 @@ export class WorkerExtHostTerminalService extends BaseExtHostTerminalService {
|
||||
}
|
||||
|
||||
public $acceptWorkspacePermissionsChanged(isAllowed: boolean): void {
|
||||
// No-op for web worker ext host as workspace permissions aren't used
|
||||
throw new NotSupportedError();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user