mirror of
https://github.com/Microsoft/vscode
synced 2024-10-12 22:37:41 +00:00
parent
fcaf9637e4
commit
25fe980387
|
@ -3,7 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { window, Terminal, Pseudoterminal, EventEmitter, TerminalDimensions, workspace, ConfigurationTarget } from 'vscode';
|
||||
import { window, Pseudoterminal, EventEmitter, TerminalDimensions, workspace, ConfigurationTarget } from 'vscode';
|
||||
import { doesNotThrow, equal, ok } from 'assert';
|
||||
|
||||
suite('window namespace tests', () => {
|
||||
|
@ -81,24 +81,6 @@ suite('window namespace tests', () => {
|
|||
});
|
||||
const terminal = window.createTerminal('b');
|
||||
});
|
||||
|
||||
test('Terminal.sendText should fire Terminal.onInput', (done) => {
|
||||
const reg1 = window.onDidOpenTerminal(terminal => {
|
||||
reg1.dispose();
|
||||
const reg2 = renderer.onDidAcceptInput(data => {
|
||||
equal(data, 'bar');
|
||||
reg2.dispose();
|
||||
const reg3 = window.onDidCloseTerminal(() => {
|
||||
reg3.dispose();
|
||||
done();
|
||||
});
|
||||
terminal.dispose();
|
||||
});
|
||||
terminal.sendText('bar', false);
|
||||
});
|
||||
const renderer = window.createTerminalRenderer('foo');
|
||||
});
|
||||
|
||||
// test('onDidChangeActiveTerminal should fire when new terminals are created', (done) => {
|
||||
// const reg1 = window.onDidChangeActiveTerminal((active: Terminal | undefined) => {
|
||||
// equal(active, terminal);
|
||||
|
@ -201,59 +183,7 @@ suite('window namespace tests', () => {
|
|||
});
|
||||
});
|
||||
|
||||
suite('Terminal renderers (deprecated)', () => {
|
||||
test('should fire onDidOpenTerminal and onDidCloseTerminal from createTerminalRenderer terminal', (done) => {
|
||||
const reg1 = window.onDidOpenTerminal(term => {
|
||||
equal(term.name, 'c');
|
||||
reg1.dispose();
|
||||
const reg2 = window.onDidCloseTerminal(() => {
|
||||
reg2.dispose();
|
||||
done();
|
||||
});
|
||||
term.dispose();
|
||||
});
|
||||
window.createTerminalRenderer('c');
|
||||
});
|
||||
|
||||
test('should get maximum dimensions set when shown', (done) => {
|
||||
let terminal: Terminal;
|
||||
const reg1 = window.onDidOpenTerminal(term => {
|
||||
reg1.dispose();
|
||||
term.show();
|
||||
terminal = term;
|
||||
});
|
||||
const renderer = window.createTerminalRenderer('foo');
|
||||
const reg2 = renderer.onDidChangeMaximumDimensions(dimensions => {
|
||||
ok(dimensions.columns > 0);
|
||||
ok(dimensions.rows > 0);
|
||||
reg2.dispose();
|
||||
const reg3 = window.onDidCloseTerminal(() => {
|
||||
reg3.dispose();
|
||||
done();
|
||||
});
|
||||
terminal.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
test('should fire Terminal.onData on write', (done) => {
|
||||
const reg1 = window.onDidOpenTerminal(terminal => {
|
||||
reg1.dispose();
|
||||
const reg2 = terminal.onDidWriteData(data => {
|
||||
equal(data, 'bar');
|
||||
reg2.dispose();
|
||||
const reg3 = window.onDidCloseTerminal(() => {
|
||||
reg3.dispose();
|
||||
done();
|
||||
});
|
||||
terminal.dispose();
|
||||
});
|
||||
renderer.write('bar');
|
||||
});
|
||||
const renderer = window.createTerminalRenderer('foo');
|
||||
});
|
||||
});
|
||||
|
||||
suite('Virtual process terminals', () => {
|
||||
suite('Extension pty terminals', () => {
|
||||
test('should fire onDidOpenTerminal and onDidCloseTerminal', (done) => {
|
||||
const reg1 = window.onDidOpenTerminal(term => {
|
||||
equal(term.name, 'c');
|
||||
|
|
155
src/vs/vscode.proposed.d.ts
vendored
155
src/vs/vscode.proposed.d.ts
vendored
|
@ -787,142 +787,6 @@ declare module 'vscode' {
|
|||
runInBackground?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the dimensions of a terminal.
|
||||
*/
|
||||
export interface TerminalDimensions {
|
||||
/**
|
||||
* The number of columns in the terminal.
|
||||
*/
|
||||
readonly columns: number;
|
||||
|
||||
/**
|
||||
* The number of rows in the terminal.
|
||||
*/
|
||||
readonly rows: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a terminal without a process where all interaction and output in the terminal is
|
||||
* controlled by an extension. This is similar to an output window but has the same VT sequence
|
||||
* compatibility as the regular terminal.
|
||||
*
|
||||
* Note that an instance of [Terminal](#Terminal) will be created when a TerminalRenderer is
|
||||
* created with all its APIs available for use by extensions. When using the Terminal object
|
||||
* of a TerminalRenderer it acts just like normal only the extension that created the
|
||||
* TerminalRenderer essentially acts as a process. For example when an
|
||||
* [Terminal.onDidWriteData](#Terminal.onDidWriteData) listener is registered, that will fire
|
||||
* when [TerminalRenderer.write](#TerminalRenderer.write) is called. Similarly when
|
||||
* [Terminal.sendText](#Terminal.sendText) is triggered that will fire the
|
||||
* [TerminalRenderer.onDidAcceptInput](#TerminalRenderer.onDidAcceptInput) event.
|
||||
*
|
||||
* @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead.
|
||||
*
|
||||
* **Example:** Create a terminal renderer, show it and write hello world in red
|
||||
* ```typescript
|
||||
* const renderer = window.createTerminalRenderer('foo');
|
||||
* renderer.terminal.then(t => t.show());
|
||||
* renderer.write('\x1b[31mHello world\x1b[0m');
|
||||
* ```
|
||||
*/
|
||||
export interface TerminalRenderer {
|
||||
/**
|
||||
* The name of the terminal, this will appear in the terminal selector.
|
||||
* @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead.
|
||||
*/
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* The dimensions of the terminal, the rows and columns of the terminal can only be set to
|
||||
* a value smaller than the maximum value, if this is undefined the terminal will auto fit
|
||||
* to the maximum value [maximumDimensions](TerminalRenderer.maximumDimensions).
|
||||
*
|
||||
* @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead.
|
||||
*
|
||||
* **Example:** Override the dimensions of a TerminalRenderer to 20 columns and 10 rows
|
||||
* ```typescript
|
||||
* terminalRenderer.dimensions = {
|
||||
* cols: 20,
|
||||
* rows: 10
|
||||
* };
|
||||
* ```
|
||||
*/
|
||||
dimensions: TerminalDimensions | undefined;
|
||||
|
||||
/**
|
||||
* The maximum dimensions of the terminal, this will be undefined immediately after a
|
||||
* terminal renderer is created and also until the terminal becomes visible in the UI.
|
||||
* Listen to [onDidChangeMaximumDimensions](TerminalRenderer.onDidChangeMaximumDimensions)
|
||||
* to get notified when this value changes.
|
||||
*
|
||||
* @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead.
|
||||
*/
|
||||
readonly maximumDimensions: TerminalDimensions | undefined;
|
||||
|
||||
/**
|
||||
* The corresponding [Terminal](#Terminal) for this TerminalRenderer.
|
||||
*
|
||||
* @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead.
|
||||
*/
|
||||
readonly terminal: Terminal;
|
||||
|
||||
/**
|
||||
* Write text to the terminal. Unlike [Terminal.sendText](#Terminal.sendText) which sends
|
||||
* text to the underlying _process_, this will write the text to the terminal itself.
|
||||
*
|
||||
* @param text The text to write.
|
||||
* @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead.
|
||||
*
|
||||
* **Example:** Write red text to the terminal
|
||||
* ```typescript
|
||||
* terminalRenderer.write('\x1b[31mHello world\x1b[0m');
|
||||
* ```
|
||||
*
|
||||
* **Example:** Move the cursor to the 10th row and 20th column and write an asterisk
|
||||
* ```typescript
|
||||
* terminalRenderer.write('\x1b[10;20H*');
|
||||
* ```
|
||||
*/
|
||||
write(text: string): void;
|
||||
|
||||
/**
|
||||
* An event which fires on keystrokes in the terminal or when an extension calls
|
||||
* [Terminal.sendText](#Terminal.sendText). Keystrokes are converted into their
|
||||
* corresponding VT sequence representation.
|
||||
*
|
||||
* @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead.
|
||||
*
|
||||
* **Example:** Simulate interaction with the terminal from an outside extension or a
|
||||
* workbench command such as `workbench.action.terminal.runSelectedText`
|
||||
* ```typescript
|
||||
* const terminalRenderer = window.createTerminalRenderer('test');
|
||||
* terminalRenderer.onDidAcceptInput(data => {
|
||||
* console.log(data); // 'Hello world'
|
||||
* });
|
||||
* terminalRenderer.terminal.sendText('Hello world');
|
||||
* ```
|
||||
*/
|
||||
readonly onDidAcceptInput: Event<string>;
|
||||
|
||||
/**
|
||||
* An event which fires when the [maximum dimensions](#TerminalRenderer.maximumDimensions) of
|
||||
* the terminal renderer change.
|
||||
*
|
||||
* @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead.
|
||||
*/
|
||||
readonly onDidChangeMaximumDimensions: Event<TerminalDimensions>;
|
||||
}
|
||||
|
||||
export namespace window {
|
||||
/**
|
||||
* Create a [TerminalRenderer](#TerminalRenderer).
|
||||
*
|
||||
* @param name The name of the terminal renderer, this shows up in the terminal selector.
|
||||
* @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead.
|
||||
*/
|
||||
export function createTerminalRenderer(name: string): TerminalRenderer;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Extension terminals
|
||||
|
@ -954,6 +818,21 @@ declare module 'vscode' {
|
|||
pty: Pseudoterminal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the dimensions of a terminal.
|
||||
*/
|
||||
export interface TerminalDimensions {
|
||||
/**
|
||||
* The number of columns in the terminal.
|
||||
*/
|
||||
readonly columns: number;
|
||||
|
||||
/**
|
||||
* The number of rows in the terminal.
|
||||
*/
|
||||
readonly rows: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the interface of a terminal pty, enabling extensions to control a terminal.
|
||||
*/
|
||||
|
@ -1169,7 +1048,7 @@ declare module 'vscode' {
|
|||
/**
|
||||
* @param callback The callback that will be called when the extension callback task is executed.
|
||||
*/
|
||||
constructor(callback: (terminalRenderer: TerminalRenderer, cancellationToken: CancellationToken, thisArg?: any) => Thenable<number>);
|
||||
constructor(callback: (terminalRenderer: any, cancellationToken: CancellationToken, thisArg?: any) => Thenable<number>);
|
||||
|
||||
/**
|
||||
* The callback used to execute the task.
|
||||
|
@ -1177,7 +1056,7 @@ declare module 'vscode' {
|
|||
* @param cancellationToken Cancellation used to signal a cancel request to the executing task.
|
||||
* @returns The callback should return '0' for success and a non-zero value for failure.
|
||||
*/
|
||||
callback: (terminalRenderer: TerminalRenderer, cancellationToken: CancellationToken, thisArg?: any) => Thenable<number>;
|
||||
callback: (terminalRenderer: any, cancellationToken: CancellationToken, thisArg?: any) => Thenable<number>;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,7 +21,6 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
|||
private readonly _terminalProcesses = new Map<number, Promise<ITerminalProcessExtHostProxy>>();
|
||||
private readonly _terminalProcessesReady = new Map<number, (proxy: ITerminalProcessExtHostProxy) => void>();
|
||||
private readonly _terminalOnDidWriteDataListeners = new Map<number, IDisposable>();
|
||||
private readonly _terminalOnDidAcceptInputListeners = new Map<number, IDisposable>();
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
|
@ -100,11 +99,6 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
|||
});
|
||||
}
|
||||
|
||||
public $createTerminalRenderer(name: string): Promise<number> {
|
||||
const instance = this._terminalService.createTerminalRenderer(name);
|
||||
return Promise.resolve(instance.id);
|
||||
}
|
||||
|
||||
public $show(terminalId: number, preserveFocus: boolean): void {
|
||||
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (terminalInstance) {
|
||||
|
@ -127,44 +121,6 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
|||
}
|
||||
}
|
||||
|
||||
public $terminalRendererWrite(terminalId: number, text: string): void {
|
||||
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);
|
||||
if (terminalInstance && terminalInstance.shellLaunchConfig.isRendererOnly) {
|
||||
terminalInstance.setTitle(name, false);
|
||||
}
|
||||
}
|
||||
|
||||
public $terminalRendererSetDimensions(terminalId: number, dimensions: ITerminalDimensions): void {
|
||||
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);
|
||||
if (!terminalInstance) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Listener already registered
|
||||
if (this._terminalOnDidAcceptInputListeners.has(terminalId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Register
|
||||
const listener = terminalInstance.onRendererInput(data => this._onTerminalRendererInput(terminalId, data));
|
||||
this._terminalOnDidAcceptInputListeners.set(terminalId, listener);
|
||||
terminalInstance.addDisposable(listener);
|
||||
}
|
||||
|
||||
public $sendText(terminalId: number, text: string, addNewLine: boolean): void {
|
||||
const terminalInstance = this._terminalService.getInstanceFromId(terminalId);
|
||||
if (terminalInstance) {
|
||||
|
@ -207,10 +163,6 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
|||
this._proxy.$acceptWorkspacePermissionsChanged(isAllowed);
|
||||
}
|
||||
|
||||
private _onTerminalRendererInput(terminalId: number, data: string): void {
|
||||
this._proxy.$acceptTerminalRendererInput(terminalId, data);
|
||||
}
|
||||
|
||||
private _onTerminalDisposed(terminalInstance: ITerminalInstance): void {
|
||||
this._proxy.$acceptTerminalClosed(terminalInstance.id);
|
||||
}
|
||||
|
|
|
@ -395,7 +395,6 @@ export interface TerminalLaunchConfig {
|
|||
|
||||
export interface MainThreadTerminalServiceShape extends IDisposable {
|
||||
$createTerminal(config: TerminalLaunchConfig): Promise<{ id: number, name: string }>;
|
||||
$createTerminalRenderer(name: string): Promise<number>;
|
||||
$dispose(terminalId: number): void;
|
||||
$hide(terminalId: number): void;
|
||||
$sendText(terminalId: number, text: string, addNewLine: boolean): void;
|
||||
|
@ -411,12 +410,6 @@ export interface MainThreadTerminalServiceShape extends IDisposable {
|
|||
$sendProcessCwd(terminalId: number, initialCwd: string): void;
|
||||
$sendOverrideDimensions(terminalId: number, dimensions: ITerminalDimensions | undefined): void;
|
||||
$sendResolvedLaunchConfig(terminalId: number, shellLaunchConfig: IShellLaunchConfig): void;
|
||||
|
||||
// Renderer
|
||||
$terminalRendererSetName(terminalId: number, name: string): void;
|
||||
$terminalRendererSetDimensions(terminalId: number, dimensions: ITerminalDimensions): void;
|
||||
$terminalRendererWrite(terminalId: number, text: string): void;
|
||||
$terminalRendererRegisterOnInputListener(terminalId: number): void;
|
||||
}
|
||||
|
||||
export interface TransferQuickPickItems extends quickInput.IQuickPickItem {
|
||||
|
@ -1158,7 +1151,6 @@ export interface ExtHostTerminalServiceShape {
|
|||
$acceptActiveTerminalChanged(id: number | null): void;
|
||||
$acceptTerminalProcessId(id: number, processId: number): void;
|
||||
$acceptTerminalProcessData(id: number, data: string): void;
|
||||
$acceptTerminalRendererInput(id: number, data: string): void;
|
||||
$acceptTerminalTitleChange(id: number, name: string): void;
|
||||
$acceptTerminalDimensions(id: number, cols: number, rows: number): void;
|
||||
$acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): void;
|
||||
|
|
|
@ -1754,9 +1754,9 @@ export enum TaskScope {
|
|||
}
|
||||
|
||||
export class CustomExecution implements vscode.CustomExecution {
|
||||
private _callback: (args: vscode.TerminalRenderer, cancellationToken: vscode.CancellationToken) => Thenable<number>;
|
||||
private _callback: (args: any, cancellationToken: vscode.CancellationToken) => Thenable<number>;
|
||||
|
||||
constructor(callback: (args: vscode.TerminalRenderer, cancellationToken: vscode.CancellationToken) => Thenable<number>) {
|
||||
constructor(callback: (args: any, cancellationToken: vscode.CancellationToken) => Thenable<number>) {
|
||||
this._callback = callback;
|
||||
}
|
||||
|
||||
|
@ -1764,11 +1764,11 @@ export class CustomExecution implements vscode.CustomExecution {
|
|||
return 'customExecution' + generateUuid();
|
||||
}
|
||||
|
||||
public set callback(value: (args: vscode.TerminalRenderer, cancellationToken: vscode.CancellationToken) => Thenable<number>) {
|
||||
public set callback(value: (args: any, cancellationToken: vscode.CancellationToken) => Thenable<number>) {
|
||||
this._callback = value;
|
||||
}
|
||||
|
||||
public get callback(): (args: vscode.TerminalRenderer, cancellationToken: vscode.CancellationToken) => Thenable<number> {
|
||||
public get callback(): (args: any, cancellationToken: vscode.CancellationToken) => Thenable<number> {
|
||||
return this._callback;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -539,9 +539,6 @@ export function createApiFactory(
|
|||
}
|
||||
return extHostTerminalService.createTerminal(<string>nameOrOptions, shellPath, shellArgs);
|
||||
},
|
||||
createTerminalRenderer(name: string): vscode.TerminalRenderer {
|
||||
return extHostTerminalService.createTerminalRenderer(name);
|
||||
},
|
||||
registerTreeDataProvider(viewId: string, treeDataProvider: vscode.TreeDataProvider<any>): vscode.Disposable {
|
||||
return extHostTreeViews.registerTreeDataProvider(viewId, treeDataProvider, extension);
|
||||
},
|
||||
|
|
|
@ -435,7 +435,7 @@ class CustomExecutionData implements IDisposable {
|
|||
}
|
||||
|
||||
this.terminal = callbackTerminals[0];
|
||||
const terminalRenderer: vscode.TerminalRenderer = await this.terminalService.resolveTerminalRenderer(terminalId);
|
||||
const terminalRenderer: any = await this.terminalService.resolveTerminalRenderer(terminalId);
|
||||
|
||||
// If we don't have the maximum dimensions yet, then we need to wait for them (but not indefinitely).
|
||||
// Custom executions will expect the dimensions to be set properly before they are launched.
|
||||
|
@ -450,7 +450,7 @@ class CustomExecutionData implements IDisposable {
|
|||
|
||||
let dimensionsRegistration: IDisposable | undefined;
|
||||
const dimensionsPromise: Promise<void> = new Promise((resolve) => {
|
||||
dimensionsRegistration = terminalRenderer.onDidChangeMaximumDimensions((newDimensions) => {
|
||||
dimensionsRegistration = terminalRenderer.onDidChangeMaximumDimensions(() => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -24,8 +24,6 @@ import { getSystemShell, detectAvailableShells } from 'vs/workbench/contrib/term
|
|||
import { getMainProcessParentEnv } from 'vs/workbench/contrib/terminal/node/terminalEnvironment';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
|
||||
const RENDERER_NO_PROCESS_ID = -1;
|
||||
|
||||
export class BaseExtHostTerminal {
|
||||
public _id: number | undefined;
|
||||
protected _idPromise: Promise<number>;
|
||||
|
@ -100,17 +98,10 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi
|
|||
constructor(
|
||||
proxy: MainThreadTerminalServiceShape,
|
||||
private _name?: string,
|
||||
id?: number,
|
||||
pid?: number
|
||||
id?: number
|
||||
) {
|
||||
super(proxy, id);
|
||||
this._pidPromise = new Promise<number>(c => {
|
||||
if (pid === RENDERER_NO_PROCESS_ID) {
|
||||
c(undefined);
|
||||
} else {
|
||||
this._pidPromiseComplete = c;
|
||||
}
|
||||
});
|
||||
this._pidPromise = new Promise<number>(c => this._pidPromiseComplete = c);
|
||||
}
|
||||
|
||||
public async create(
|
||||
|
@ -201,92 +192,11 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi
|
|||
}
|
||||
}
|
||||
|
||||
export class ExtHostTerminalRenderer extends BaseExtHostTerminal implements vscode.TerminalRenderer {
|
||||
public get name(): string { return this._name; }
|
||||
public set name(newName: string) {
|
||||
this._name = newName;
|
||||
this._checkDisposed();
|
||||
this._queueApiRequest(this._proxy.$terminalRendererSetName, [this._name]);
|
||||
}
|
||||
|
||||
private readonly _onInput = new Emitter<string>();
|
||||
public get onDidAcceptInput(): Event<string> {
|
||||
this._checkDisposed();
|
||||
this._queueApiRequest(this._proxy.$terminalRendererRegisterOnInputListener, [this._id]);
|
||||
// Tell the main side to start sending data if it's not already
|
||||
// this._proxy.$terminalRendererRegisterOnDataListener(this._id);
|
||||
return this._onInput && this._onInput.event;
|
||||
}
|
||||
|
||||
private _dimensions: vscode.TerminalDimensions | undefined;
|
||||
public get dimensions(): vscode.TerminalDimensions | undefined { return this._dimensions; }
|
||||
public set dimensions(dimensions: vscode.TerminalDimensions | undefined) {
|
||||
this._checkDisposed();
|
||||
this._dimensions = dimensions;
|
||||
this._queueApiRequest(this._proxy.$terminalRendererSetDimensions, [dimensions]);
|
||||
}
|
||||
|
||||
private _maximumDimensions: vscode.TerminalDimensions | undefined;
|
||||
public get maximumDimensions(): vscode.TerminalDimensions | undefined {
|
||||
if (!this._maximumDimensions) {
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
rows: this._maximumDimensions.rows,
|
||||
columns: this._maximumDimensions.columns
|
||||
};
|
||||
}
|
||||
|
||||
private readonly _onDidChangeMaximumDimensions: Emitter<vscode.TerminalDimensions> = new Emitter<vscode.TerminalDimensions>();
|
||||
public get onDidChangeMaximumDimensions(): Event<vscode.TerminalDimensions> {
|
||||
return this._onDidChangeMaximumDimensions && this._onDidChangeMaximumDimensions.event;
|
||||
}
|
||||
|
||||
public get terminal(): ExtHostTerminal {
|
||||
return this._terminal;
|
||||
}
|
||||
|
||||
constructor(
|
||||
proxy: MainThreadTerminalServiceShape,
|
||||
private _name: string,
|
||||
private _terminal: ExtHostTerminal,
|
||||
id?: number
|
||||
) {
|
||||
super(proxy, id);
|
||||
|
||||
if (!id) {
|
||||
this._proxy.$createTerminalRenderer(this._name).then(id => {
|
||||
this._runQueuedRequests(id);
|
||||
(<any>this._terminal)._runQueuedRequests(id);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public write(data: string): void {
|
||||
this._checkDisposed();
|
||||
this._queueApiRequest(this._proxy.$terminalRendererWrite, [data]);
|
||||
}
|
||||
|
||||
public _fireOnInput(data: string): void {
|
||||
this._onInput.fire(data);
|
||||
}
|
||||
|
||||
public _setMaximumDimensions(columns: number, rows: number): void {
|
||||
if (this._maximumDimensions && this._maximumDimensions.columns === columns && this._maximumDimensions.rows === rows) {
|
||||
return;
|
||||
}
|
||||
const newValue = { columns, rows };
|
||||
this._maximumDimensions = newValue;
|
||||
this._onDidChangeMaximumDimensions.fire(newValue);
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
||||
private _proxy: MainThreadTerminalServiceShape;
|
||||
private _activeTerminal: ExtHostTerminal | undefined;
|
||||
private _terminals: ExtHostTerminal[] = [];
|
||||
private _terminalProcesses: { [id: number]: ITerminalChildProcess } = {};
|
||||
private _terminalRenderers: ExtHostTerminalRenderer[] = [];
|
||||
private _getTerminalPromises: { [id: number]: Promise<ExtHostTerminal> } = {};
|
||||
private _variableResolver: ExtHostVariableResolverService | undefined;
|
||||
private _lastActiveWorkspace: IWorkspaceFolder | undefined;
|
||||
|
@ -350,17 +260,6 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
|||
this._setupExtHostProcessListeners(id, p);
|
||||
}
|
||||
|
||||
public createTerminalRenderer(name: string): vscode.TerminalRenderer {
|
||||
const terminal = new ExtHostTerminal(this._proxy, name);
|
||||
terminal._setProcessId(undefined);
|
||||
this._terminals.push(terminal);
|
||||
|
||||
const renderer = new ExtHostTerminalRenderer(this._proxy, name, terminal);
|
||||
this._terminalRenderers.push(renderer);
|
||||
|
||||
return renderer;
|
||||
}
|
||||
|
||||
public getDefaultShell(configProvider: ExtHostConfigProvider): string {
|
||||
const fetchSetting = (key: string) => {
|
||||
const setting = configProvider
|
||||
|
@ -391,22 +290,9 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
|||
return terminalEnvironment.getDefaultShellArgs(fetchSetting, this._isWorkspaceShellAllowed, this._lastActiveWorkspace, this._variableResolver, this._logService);
|
||||
}
|
||||
|
||||
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) {
|
||||
if (terminalRenderer._id === id) {
|
||||
return terminalRenderer;
|
||||
}
|
||||
}
|
||||
|
||||
const terminal = this._getTerminalById(id);
|
||||
if (!terminal) {
|
||||
throw new Error(`Cannot resolve terminal renderer for terminal id ${id}`);
|
||||
}
|
||||
const renderer = new ExtHostTerminalRenderer(this._proxy, terminal.name, terminal, terminal._id);
|
||||
this._terminalRenderers.push(renderer);
|
||||
|
||||
return renderer;
|
||||
// TODO: Remove when CustomExecution is removed
|
||||
public async resolveTerminalRenderer(id: number): Promise<any> {
|
||||
throw new Error('TerminalRenderers are no longer supported');
|
||||
}
|
||||
|
||||
public $acceptActiveTerminalChanged(id: number | null): void {
|
||||
|
@ -454,22 +340,6 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
|||
// Virtual processes only - when virtual process resize fires it means that the
|
||||
// terminal's maximum dimensions changed
|
||||
this._terminalProcesses[id].resize(cols, rows);
|
||||
} else {
|
||||
// Terminal renderer
|
||||
this._getTerminalByIdEventually(id).then(() => {
|
||||
// When a terminal's dimensions change, a renderer's _maximum_ dimensions change
|
||||
const renderer = this._getTerminalRendererById(id);
|
||||
if (renderer) {
|
||||
renderer._setMaximumDimensions(cols, rows);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public $acceptTerminalRendererInput(id: number, data: string): void {
|
||||
const renderer = this._getTerminalRendererById(id);
|
||||
if (renderer) {
|
||||
renderer._fireOnInput(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -496,8 +366,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
|||
return;
|
||||
}
|
||||
|
||||
const renderer = this._getTerminalRendererById(id);
|
||||
const terminal = new ExtHostTerminal(this._proxy, name, id, renderer ? RENDERER_NO_PROCESS_ID : undefined);
|
||||
const terminal = new ExtHostTerminal(this._proxy, name, id);
|
||||
this._terminals.push(terminal);
|
||||
this._onDidOpenTerminal.fire(terminal);
|
||||
}
|
||||
|
@ -739,16 +608,12 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
|||
return this._getTerminalObjectById(this._terminals, id);
|
||||
}
|
||||
|
||||
private _getTerminalRendererById(id: number): ExtHostTerminalRenderer | null {
|
||||
return this._getTerminalObjectById(this._terminalRenderers, id);
|
||||
}
|
||||
|
||||
private _getTerminalObjectById<T extends ExtHostTerminal | ExtHostTerminalRenderer>(array: T[], id: number): T | null {
|
||||
private _getTerminalObjectById<T extends ExtHostTerminal>(array: T[], id: number): T | null {
|
||||
const index = this._getTerminalObjectIndexById(array, id);
|
||||
return index !== null ? array[index] : null;
|
||||
}
|
||||
|
||||
private _getTerminalObjectIndexById<T extends ExtHostTerminal | ExtHostTerminalRenderer>(array: T[], id: number): number | null {
|
||||
private _getTerminalObjectIndexById<T extends ExtHostTerminal>(array: T[], id: number): number | null {
|
||||
let index: number | null = null;
|
||||
array.some((item, i) => {
|
||||
const thisId = item._id;
|
||||
|
|
|
@ -285,7 +285,7 @@ export class TerminalTaskSystem implements ITaskSystem {
|
|||
}
|
||||
|
||||
return new Promise<void>((resolve) => {
|
||||
activeTerminal.terminal.rendererExit(result);
|
||||
// activeTerminal.terminal.rendererExit(result);
|
||||
resolve();
|
||||
});
|
||||
}
|
||||
|
@ -918,12 +918,13 @@ export class TerminalTaskSystem implements ITaskSystem {
|
|||
let launchConfigs: IShellLaunchConfig | undefined;
|
||||
|
||||
if (task.command.runtime === RuntimeType.CustomExecution) {
|
||||
this.currentTask.shellLaunchConfig = launchConfigs = {
|
||||
isRendererOnly: true,
|
||||
waitOnExit,
|
||||
name: this.createTerminalName(task, workspaceFolder),
|
||||
initialText: task.command.presentation && task.command.presentation.echo ? `\x1b[1m> Executing task: ${task._label} <\x1b[0m\n` : undefined
|
||||
};
|
||||
throw new Error('CustomExecution is no longer supported');
|
||||
// this.currentTask.shellLaunchConfig = launchConfigs = {
|
||||
// isRendererOnly: true,
|
||||
// waitOnExit,
|
||||
// name: this.createTerminalName(task, workspaceFolder),
|
||||
// initialText: task.command.presentation && task.command.presentation.echo ? `\x1b[1m> Executing task: ${task._label} <\x1b[0m\n` : undefined
|
||||
// };
|
||||
} else if (task.command.runtime === RuntimeType.CustomExecution2) {
|
||||
this.currentTask.shellLaunchConfig = launchConfigs = {
|
||||
isExtensionTerminal: true,
|
||||
|
|
|
@ -172,7 +172,7 @@ export class TerminalInstance implements ITerminalInstance {
|
|||
private static _lastKnownGridDimensions: IGridDimensions | undefined;
|
||||
private static _idCounter = 1;
|
||||
|
||||
private _processManager: ITerminalProcessManager | undefined;
|
||||
private _processManager: ITerminalProcessManager;
|
||||
private _pressAnyKeyToCloseListener: lifecycle.IDisposable | undefined;
|
||||
|
||||
private _id: number;
|
||||
|
@ -246,8 +246,6 @@ export class TerminalInstance implements ITerminalInstance {
|
|||
public get onData(): Event<string> { return this._onData.event; }
|
||||
private readonly _onLineData = new Emitter<string>();
|
||||
public get onLineData(): Event<string> { return this._onLineData.event; }
|
||||
private readonly _onRendererInput = new Emitter<string>();
|
||||
public get onRendererInput(): Event<string> { return this._onRendererInput.event; }
|
||||
private readonly _onRequestExtHostProcess = new Emitter<ITerminalInstance>();
|
||||
public get onRequestExtHostProcess(): Event<ITerminalInstance> { return this._onRequestExtHostProcess.event; }
|
||||
private readonly _onDimensionsChanged = new Emitter<void>();
|
||||
|
@ -293,11 +291,7 @@ export class TerminalInstance implements ITerminalInstance {
|
|||
this._logService.trace(`terminalInstance#ctor (id: ${this.id})`, this._shellLaunchConfig);
|
||||
|
||||
this._initDimensions();
|
||||
if (!this.shellLaunchConfig.isRendererOnly) {
|
||||
this._createProcess();
|
||||
} else {
|
||||
this.setTitle(this._shellLaunchConfig.name, false);
|
||||
}
|
||||
this._createProcess();
|
||||
|
||||
this._xtermReadyPromise = this._createXterm();
|
||||
this._xtermReadyPromise.then(() => {
|
||||
|
@ -488,39 +482,30 @@ export class TerminalInstance implements ITerminalInstance {
|
|||
this._xterm.onLineFeed(() => this._onLineFeed());
|
||||
this._xterm.onKey(e => this._onKey(e.key, e.domEvent));
|
||||
|
||||
if (this._processManager) {
|
||||
this._processManager.onProcessData(data => this._onProcessData(data));
|
||||
this._xterm.onData(data => this._processManager!.write(data));
|
||||
// TODO: How does the cwd work on detached processes?
|
||||
this.processReady.then(async () => {
|
||||
this._linkHandler.processCwd = await this._processManager!.getInitialCwd();
|
||||
});
|
||||
// Init winpty compat and link handler after process creation as they rely on the
|
||||
// underlying process OS
|
||||
this._processManager.onProcessReady(() => {
|
||||
if (!this._processManager) {
|
||||
return;
|
||||
}
|
||||
if (this._processManager.os === platform.OperatingSystem.Windows) {
|
||||
xterm.setOption('windowsMode', true);
|
||||
// Force line data to be sent when the cursor is moved, the main purpose for
|
||||
// this is because ConPTY will often not do a line feed but instead move the
|
||||
// cursor, in which case we still want to send the current line's data to tasks.
|
||||
xterm.addCsiHandler('H', () => {
|
||||
this._onCursorMove();
|
||||
return false;
|
||||
});
|
||||
}
|
||||
this._linkHandler = this._instantiationService.createInstance(TerminalLinkHandler, this._xterm, this._processManager, this._configHelper);
|
||||
});
|
||||
} else if (this.shellLaunchConfig.isRendererOnly) {
|
||||
this._linkHandler = this._instantiationService.createInstance(TerminalLinkHandler, this._xterm, undefined, this._configHelper);
|
||||
}
|
||||
|
||||
// Register listener to trigger the onInput ext API if the terminal is a renderer only
|
||||
if (this._shellLaunchConfig.isRendererOnly) {
|
||||
this._xterm.onData(data => this._sendRendererInput(data));
|
||||
}
|
||||
this._processManager.onProcessData(data => this._onProcessData(data));
|
||||
this._xterm.onData(data => this._processManager!.write(data));
|
||||
// TODO: How does the cwd work on detached processes?
|
||||
this.processReady.then(async () => {
|
||||
this._linkHandler.processCwd = await this._processManager!.getInitialCwd();
|
||||
});
|
||||
// Init winpty compat and link handler after process creation as they rely on the
|
||||
// underlying process OS
|
||||
this._processManager.onProcessReady(() => {
|
||||
if (!this._processManager) {
|
||||
return;
|
||||
}
|
||||
if (this._processManager.os === platform.OperatingSystem.Windows) {
|
||||
xterm.setOption('windowsMode', true);
|
||||
// Force line data to be sent when the cursor is moved, the main purpose for
|
||||
// this is because ConPTY will often not do a line feed but instead move the
|
||||
// cursor, in which case we still want to send the current line's data to tasks.
|
||||
xterm.addCsiHandler('H', () => {
|
||||
this._onCursorMove();
|
||||
return false;
|
||||
});
|
||||
}
|
||||
this._linkHandler = this._instantiationService.createInstance(TerminalLinkHandler, this._xterm, this._processManager, this._configHelper);
|
||||
});
|
||||
|
||||
this._commandTrackerAddon = new CommandTrackerAddon();
|
||||
this._xterm.loadAddon(this._commandTrackerAddon);
|
||||
|
@ -659,13 +644,8 @@ export class TerminalInstance implements ITerminalInstance {
|
|||
this._wrapperElement.appendChild(this._xtermElement);
|
||||
this._container.appendChild(this._wrapperElement);
|
||||
|
||||
if (this._processManager) {
|
||||
this._widgetManager = new TerminalWidgetManager(this._wrapperElement);
|
||||
this._processManager.onProcessReady(() => this._linkHandler.setWidgetManager(this._widgetManager));
|
||||
} else if (this._shellLaunchConfig.isRendererOnly) {
|
||||
this._widgetManager = new TerminalWidgetManager(this._wrapperElement);
|
||||
this._linkHandler.setWidgetManager(this._widgetManager);
|
||||
}
|
||||
this._widgetManager = new TerminalWidgetManager(this._wrapperElement);
|
||||
this._processManager.onProcessReady(() => this._linkHandler.setWidgetManager(this._widgetManager));
|
||||
|
||||
const computedStyle = window.getComputedStyle(this._container);
|
||||
const width = parseInt(computedStyle.getPropertyValue('width').replace('px', ''), 10);
|
||||
|
@ -844,16 +824,6 @@ export class TerminalInstance implements ITerminalInstance {
|
|||
this._disposables.dispose();
|
||||
}
|
||||
|
||||
public rendererExit(exitCode: number): void {
|
||||
// The use of this API is for cases where there is no backing process behind a terminal
|
||||
// instance (e.g. a custom execution task).
|
||||
if (!this.shellLaunchConfig.isRendererOnly) {
|
||||
throw new Error('rendererExit is only expected to be called on a renderer only terminal');
|
||||
}
|
||||
|
||||
return this._onProcessExit(exitCode);
|
||||
}
|
||||
|
||||
public forceRedraw(): void {
|
||||
if (!this._xterm) {
|
||||
return;
|
||||
|
@ -902,10 +872,6 @@ export class TerminalInstance implements ITerminalInstance {
|
|||
return;
|
||||
}
|
||||
this._xterm.write(text);
|
||||
if (this._shellLaunchConfig.isRendererOnly) {
|
||||
// Fire onData API in the extension host
|
||||
this._onData.fire(text);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -916,16 +882,11 @@ export class TerminalInstance implements ITerminalInstance {
|
|||
text += '\r';
|
||||
}
|
||||
|
||||
if (this._shellLaunchConfig.isRendererOnly) {
|
||||
// If the terminal is a renderer only, fire the onInput ext API
|
||||
this._sendRendererInput(text);
|
||||
} else {
|
||||
// If the terminal has a process, send it to the process
|
||||
if (this._processManager) {
|
||||
this._processManager.ptyProcessReady.then(() => {
|
||||
this._processManager!.write(text);
|
||||
});
|
||||
}
|
||||
// If the terminal has a process, send it to the process
|
||||
if (this._processManager) {
|
||||
this._processManager.ptyProcessReady.then(() => {
|
||||
this._processManager!.write(text);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1159,7 +1120,6 @@ export class TerminalInstance implements ITerminalInstance {
|
|||
// Kill and clear up the process, making the process manager ready for a new process
|
||||
if (this._processManager) {
|
||||
this._processManager.dispose();
|
||||
this._processManager = undefined;
|
||||
}
|
||||
|
||||
if (this._xterm) {
|
||||
|
@ -1184,11 +1144,7 @@ export class TerminalInstance implements ITerminalInstance {
|
|||
// Launch the process unless this is only a renderer.
|
||||
// In the renderer only cases, we still need to set the title correctly.
|
||||
const oldTitle = this._title;
|
||||
if (!this._shellLaunchConfig.isRendererOnly) {
|
||||
this._createProcess();
|
||||
} else if (this._shellLaunchConfig.name) {
|
||||
this.setTitle(this._shellLaunchConfig.name, false);
|
||||
}
|
||||
this._createProcess();
|
||||
|
||||
if (oldTitle !== this._title) {
|
||||
this.setTitle(this._title, true);
|
||||
|
@ -1201,15 +1157,6 @@ export class TerminalInstance implements ITerminalInstance {
|
|||
}
|
||||
}
|
||||
|
||||
private _sendRendererInput(input: string): void {
|
||||
if (this._processManager) {
|
||||
throw new Error('onRendererInput attempted to be used on a regular terminal');
|
||||
}
|
||||
|
||||
// For terminal renderers onData fires on keystrokes and when sendText is called.
|
||||
this._onRendererInput.fire(input);
|
||||
}
|
||||
|
||||
private _onLineFeed(): void {
|
||||
const buffer = this._xterm!.buffer;
|
||||
const newLine = buffer.getLine(buffer.baseY + buffer.cursorY);
|
||||
|
|
|
@ -187,11 +187,6 @@ export interface IShellLaunchConfig {
|
|||
*/
|
||||
initialText?: string;
|
||||
|
||||
/**
|
||||
* @deprecated use `isExtensionTerminal`
|
||||
*/
|
||||
isRendererOnly?: boolean;
|
||||
|
||||
/**
|
||||
* Whether an extension is controlling the terminal via a `vscode.Pseudoterminal`.
|
||||
*/
|
||||
|
@ -244,12 +239,6 @@ export interface ITerminalService {
|
|||
*/
|
||||
createTerminal(shell?: IShellLaunchConfig): ITerminalInstance;
|
||||
|
||||
/**
|
||||
* Creates a terminal renderer.
|
||||
* @param name The name of the terminal.
|
||||
*/
|
||||
createTerminalRenderer(name: string): ITerminalInstance;
|
||||
|
||||
/**
|
||||
* Creates a raw terminal instance, this should not be used outside of the terminal part.
|
||||
*/
|
||||
|
@ -422,13 +411,6 @@ export interface ITerminalInstance {
|
|||
*/
|
||||
onData: Event<string>;
|
||||
|
||||
/**
|
||||
* Attach a listener to the "renderer" input event, this event fires for terminal renderers on
|
||||
* keystrokes and when the Terminal.sendText extension API is used.
|
||||
* @param listener The listener function.
|
||||
*/
|
||||
onRendererInput: Event<string>;
|
||||
|
||||
/**
|
||||
* Attach a listener to listen for new lines added to this terminal instance.
|
||||
*
|
||||
|
@ -497,14 +479,6 @@ export interface ITerminalInstance {
|
|||
*/
|
||||
dispose(immediate?: boolean): void;
|
||||
|
||||
/**
|
||||
* Indicates that a consumer of a renderer only terminal is finished with it.
|
||||
*
|
||||
* @param exitCode The exit code of the terminal. Zero indicates success, non-zero indicates
|
||||
* failure.
|
||||
*/
|
||||
rendererExit(exitCode: number): void;
|
||||
|
||||
/**
|
||||
* Forces the terminal to redraw its viewport.
|
||||
*/
|
||||
|
|
|
@ -126,10 +126,6 @@ export abstract class TerminalService implements ITerminalService {
|
|||
public abstract createInstance(terminalFocusContextKey: IContextKey<boolean>, configHelper: ITerminalConfigHelper, container: HTMLElement, shellLaunchConfig: IShellLaunchConfig): ITerminalInstance;
|
||||
public abstract setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void;
|
||||
|
||||
public createTerminalRenderer(name: string): ITerminalInstance {
|
||||
return this.createTerminal({ name, isRendererOnly: true });
|
||||
}
|
||||
|
||||
public getActiveOrCreateInstance(wasNewTerminalAction?: boolean): ITerminalInstance {
|
||||
const activeInstance = this.getActiveInstance();
|
||||
return activeInstance ? activeInstance : this.createTerminal(undefined, wasNewTerminalAction);
|
||||
|
|
Loading…
Reference in a new issue