未验证 提交 111c704e 编写于 作者: D Daniel Imms 提交者: GitHub

Merge pull request #67919 from Microsoft/tyriar/55718_terminal_dimensions

Add Terminal.dimensions and window.onDidChangeTerminalDimensions proposed APIs
......@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { workspace, window, commands, ViewColumn, TextEditorViewColumnChangeEvent, Uri, Selection, Position, CancellationTokenSource, TextEditorSelectionChangeKind, Terminal } from 'vscode';
import { workspace, window, commands, ViewColumn, TextEditorViewColumnChangeEvent, Uri, Selection, Position, CancellationTokenSource, TextEditorSelectionChangeKind, Terminal, TerminalDimensionsChangeEvent } from 'vscode';
import { join } from 'path';
import { closeAllEditors, pathEquals, createRandomFile } from '../utils';
......@@ -695,6 +695,45 @@ suite('window namespace tests', () => {
const terminal = window.createTerminal();
terminal.show();
});
test('onDidChangeTerminalDimensions should fire when new terminals are created', (done) => {
const reg1 = window.onDidChangeTerminalDimensions((event: TerminalDimensionsChangeEvent) => {
assert.equal(event.terminal, terminal1);
assert.equal(typeof event.dimensions.columns, 'number');
assert.equal(typeof event.dimensions.rows, 'number');
assert.ok(event.dimensions.columns > 0);
assert.ok(event.dimensions.rows > 0);
reg1.dispose();
let terminal2: Terminal;
const reg2 = window.onDidOpenTerminal((newTerminal) => {
// THis is guarentees to fire before dimensions change event
if (newTerminal !== terminal1) {
terminal2 = newTerminal;
reg2.dispose();
}
});
let firstCalled = false;
let secondCalled = false;
const reg3 = window.onDidChangeTerminalDimensions((event: TerminalDimensionsChangeEvent) => {
if (event.terminal === terminal1) {
// The original terminal should fire dimension change after a split
firstCalled = true;
} else if (event.terminal !== terminal1) {
// The new split terminal should fire dimension change
secondCalled = true;
}
if (firstCalled && secondCalled) {
terminal1.dispose();
terminal2.dispose();
reg3.dispose();
done();
}
});
commands.executeCommand('workbench.action.terminal.split');
});
const terminal1 = window.createTerminal({ name: 'test' });
terminal1.show();
});
});
});
......
......@@ -888,13 +888,41 @@ declare module 'vscode' {
//#region Terminal
/**
* An [event](#Event) which fires when a [Terminal](#Terminal)'s dimensions change.
*/
export interface TerminalDimensionsChangeEvent {
/**
* The [terminal](#Terminal) for which the dimensions have changed.
*/
readonly terminal: Terminal;
/**
* The new value for the [terminal's dimensions](#Terminal.dimensions).
*/
readonly dimensions: TerminalDimensions;
}
namespace window {
/**
* An event which fires when the [dimensions](#Terminal.dimensions) of the terminal change.
*/
export const onDidChangeTerminalDimensions: Event<TerminalDimensionsChangeEvent>;
}
export interface Terminal {
/**
* The current dimensions of the terminal. This will be `undefined` immediately after the
* terminal is created as the dimensions are not known until shortly after the terminal is
* created.
*/
readonly dimensions: TerminalDimensions | undefined;
/**
* Fires when the terminal's pty slave pseudo-device is written to. In other words, this
* provides access to the raw data stream from the process running within the terminal,
* including VT sequences.
*/
onDidWriteData: Event<string>;
readonly onDidWriteData: Event<string>;
}
/**
......
......@@ -28,7 +28,10 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
// 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.
setTimeout(() => this._onTerminalOpened(instance), EXT_HOST_CREATION_DELAY);
setTimeout(() => {
this._onTerminalOpened(instance);
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)));
......@@ -196,11 +199,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
}
private _onInstanceDimensionsChanged(instance: ITerminalInstance): void {
// Only send the dimensions if the terminal is a renderer only as there is no API to access
// dimensions on a plain Terminal.
if (instance.shellLaunchConfig.isRendererOnly) {
this._proxy.$acceptTerminalRendererDimensions(instance.id, instance.cols, instance.rows);
}
this._proxy.$acceptTerminalDimensions(instance.id, instance.cols, instance.rows);
}
private _onTerminalRequestExtHostProcess(request: ITerminalProcessExtHostRequest): void {
......
......@@ -424,6 +424,9 @@ export function createApiFactory(
onDidChangeActiveTerminal(listener, thisArg?, disposables?) {
return extHostTerminalService.onDidChangeActiveTerminal(listener, thisArg, disposables);
},
onDidChangeTerminalDimensions(listener, thisArg?, disposables?) {
return extHostTerminalService.onDidChangeTerminalDimensions(listener, thisArg, disposables);
},
get state() {
return extHostWindow.state;
},
......@@ -479,9 +482,9 @@ export function createApiFactory(
}
return extHostTerminalService.createTerminal(<string>nameOrOptions, shellPath, shellArgs);
},
createTerminalRenderer: proposedApiFunction(extension, (name: string) => {
createTerminalRenderer(name: string): vscode.TerminalRenderer {
return extHostTerminalService.createTerminalRenderer(name);
}),
},
registerTreeDataProvider(viewId: string, treeDataProvider: vscode.TreeDataProvider<any>): vscode.Disposable {
return extHostTreeViews.registerTreeDataProvider(viewId, treeDataProvider, extension);
},
......
......@@ -935,7 +935,7 @@ export interface ExtHostTerminalServiceShape {
$acceptTerminalProcessData(id: number, data: string): void;
$acceptTerminalRendererInput(id: number, data: string): void;
$acceptTerminalTitleChange(id: number, name: string): void;
$acceptTerminalRendererDimensions(id: number, cols: number, rows: number): void;
$acceptTerminalDimensions(id: number, cols: number, rows: number): void;
$createProcess(id: number, shellLaunchConfig: ShellLaunchConfigDto, activeWorkspaceRootUri: URI, cols: number, rows: number): void;
$acceptProcessInput(id: number, data: string): void;
$acceptProcessResize(id: number, cols: number, rows: number): void;
......
......@@ -78,6 +78,8 @@ export class BaseExtHostTerminal {
export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Terminal {
private _pidPromise: Promise<number>;
private _pidPromiseComplete: (value: number) => any;
private _cols: number | undefined;
private _rows: number | undefined;
private readonly _onData = new Emitter<string>();
public get onDidWriteData(): Event<string> {
......@@ -126,6 +128,26 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi
this._name = name;
}
public get dimensions(): vscode.TerminalDimensions | undefined {
if (this._cols === undefined && this._rows === undefined) {
return undefined;
}
return {
columns: this._cols,
rows: this._rows
};
}
public setDimensions(cols: number, rows: number): boolean {
if (cols === this._cols && rows === this._rows) {
// Nothing changed
return false;
}
this._cols = cols;
this._rows = rows;
return true;
}
public get processId(): Promise<number> {
return this._pidPromise;
}
......@@ -258,6 +280,8 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
public get onDidOpenTerminal(): Event<vscode.Terminal> { return this._onDidOpenTerminal && this._onDidOpenTerminal.event; }
private readonly _onDidChangeActiveTerminal: Emitter<vscode.Terminal | undefined> = new Emitter<vscode.Terminal | undefined>();
public get onDidChangeActiveTerminal(): Event<vscode.Terminal | undefined> { return this._onDidChangeActiveTerminal && this._onDidChangeActiveTerminal.event; }
private readonly _onDidChangeTerminalDimensions: Emitter<vscode.TerminalDimensionsChangeEvent> = new Emitter<vscode.TerminalDimensionsChangeEvent>();
public get onDidChangeTerminalDimensions(): Event<vscode.TerminalDimensionsChangeEvent> { return this._onDidChangeTerminalDimensions && this._onDidChangeTerminalDimensions.event; }
constructor(
mainContext: IMainContext,
......@@ -319,7 +343,17 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
});
}
public $acceptTerminalRendererDimensions(id: number, cols: number, rows: number): void {
public async $acceptTerminalDimensions(id: number, cols: number, rows: number): Promise<void> {
const terminal = this._getTerminalById(id);
if (terminal) {
if (terminal.setDimensions(cols, rows)) {
this._onDidChangeTerminalDimensions.fire({
terminal: terminal,
dimensions: terminal.dimensions
});
}
}
// When a terminal's dimensions change, a renderer's _maximum_ dimensions change
const renderer = this._getTerminalRendererById(id);
if (renderer) {
renderer._setMaximumDimensions(cols, rows);
......
......@@ -190,8 +190,18 @@ export class TerminalInstance implements ITerminalInstance {
public disableLayout: boolean;
public get id(): number { return this._id; }
public get cols(): number { return this._cols; }
public get rows(): number { return this._rows; }
public get cols(): number {
if (this._dimensionsOverride && this._dimensionsOverride.cols) {
return Math.min(Math.max(this._dimensionsOverride.cols, 2), this._cols);
}
return this._cols;
}
public get rows(): number {
if (this._dimensionsOverride && this._dimensionsOverride.rows) {
return Math.min(Math.max(this._dimensionsOverride.rows, 2), this._rows);
}
return this._rows;
}
// TODO: Ideally processId would be merged into processReady
public get processId(): number | undefined { return this._processManager ? this._processManager.shellProcessId : undefined; }
// TODO: How does this work with detached processes?
......@@ -1173,6 +1183,7 @@ export class TerminalInstance implements ITerminalInstance {
return;
}
const terminalWidth = this._evaluateColsAndRows(dimension.width, dimension.height);
if (!terminalWidth) {
return;
......@@ -1187,12 +1198,8 @@ export class TerminalInstance implements ITerminalInstance {
@debounce(50)
private _resize(): void {
let cols = this._cols;
let rows = this._rows;
if (this._dimensionsOverride && this._dimensionsOverride.cols && this._dimensionsOverride.rows) {
cols = Math.min(Math.max(this._dimensionsOverride.cols, 2), cols);
rows = Math.min(Math.max(this._dimensionsOverride.rows, 2), rows);
}
let cols = this.cols;
let rows = this.rows;
if (this._xterm) {
// Only apply these settings when the terminal is visible so that
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册