提交 166f41a2 编写于 作者: D Daniel Imms

Add support for dimensions APIs

上级 bae15f1d
......@@ -344,6 +344,21 @@ declare module 'vscode' {
onData: Event<string>;
}
/**
* Represents dimensions of a terminal.
*/
export interface TerminalDimensions {
/**
* The number of columns in the terminal.
*/
cols: number;
/**
* The number of rows in the terminal.
*/
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
......@@ -355,8 +370,20 @@ declare module 'vscode' {
*/
name: string;
// Setting to undefined will reset to use the maximum available
// dimensions: TerminalDimensions;
/**
* 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).
*/
dimensions: TerminalDimensions;
/**
* 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.
*/
readonly maximumDimensions: TerminalDimensions;
/**
* Write text to the terminal. Unlike [Terminal.sendText](#Terminal.sendText) which sends
......@@ -385,7 +412,11 @@ declare module 'vscode' {
onData: Event<string>; // in
// Fires when the panel area is resized, this DOES NOT fire when `dimensions` is set
// onDidChangeDimensions: Event<TerminalDimensions>;
/**
* An event which fires when the [maximum dimensions](#TerminalRenderer.maimumDimensions) of
* the terminal renderer change.
*/
onDidChangeMaximumDimensions: Event<TerminalDimensions>;
}
export namespace window {
......
......@@ -5,7 +5,7 @@
'use strict';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest } from 'vs/workbench/parts/terminal/common/terminal';
import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, ITerminalDimensions } from 'vs/workbench/parts/terminal/common/terminal';
import { TPromise } from 'vs/base/common/winjs.base';
import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, ShellLaunchConfigDto } from '../node/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers';
......@@ -24,14 +24,15 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
@ITerminalService private terminalService: ITerminalService
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTerminalService);
this._toDispose.push(terminalService.onInstanceCreated((terminalInstance) => {
this._toDispose.push(terminalService.onInstanceCreated((instance) => {
// 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(terminalInstance), 100);
setTimeout(() => this._onTerminalOpened(instance), 100);
}));
this._toDispose.push(terminalService.onInstanceDisposed(terminalInstance => this._onTerminalDisposed(terminalInstance)));
this._toDispose.push(terminalService.onInstanceProcessIdReady(terminalInstance => this._onTerminalProcessIdReady(terminalInstance)));
this._toDispose.push(terminalService.onInstanceDisposed(instance => this._onTerminalDisposed(instance)));
this._toDispose.push(terminalService.onInstanceProcessIdReady(instance => this._onTerminalProcessIdReady(instance)));
this._toDispose.push(terminalService.onInstanceDimensionsChanged(instance => this._onInstanceDimensionsChanged(instance)));
this._toDispose.push(terminalService.onInstanceRequestExtHostProcess(request => this._onTerminalRequestExtHostProcess(request)));
// Set initial ext host state
......@@ -62,7 +63,8 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
}
public $createTerminalRenderer(name: string): TPromise<number> {
return TPromise.as(this.terminalService.createTerminalRenderer(name).id);
const instance = this.terminalService.createTerminalRenderer(name);
return TPromise.as(instance.id);
}
public $show(terminalId: number, preserveFocus: boolean): void {
......@@ -100,6 +102,13 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
}
}
public $terminalRendererSetDimensions(terminalId: number, dimensions: ITerminalDimensions): void {
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
if (terminalInstance && terminalInstance.shellLaunchConfig.isRendererOnly) {
terminalInstance.setDimensions(dimensions);
}
}
public $terminalRendererRegisterOnDataListener(terminalId: number): void {
const terminalInstance = this.terminalService.getInstanceFromId(terminalId);
if (terminalInstance) {
......@@ -143,6 +152,14 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
this._proxy.$acceptTerminalProcessId(terminalInstance.id, terminalInstance.processId);
}
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);
}
}
private _onTerminalRequestExtHostProcess(request: ITerminalProcessExtHostRequest): void {
this._terminalProcesses[request.proxy.terminalId] = request.proxy;
const shellLaunchConfigDto: ShellLaunchConfigDto = {
......
......@@ -49,6 +49,7 @@ import { ISingleEditOperation } from 'vs/editor/common/model';
import { IPatternInfo, IRawSearchQuery, IRawFileMatch2, ISearchCompleteStats } from 'vs/platform/search/common/search';
import { LogLevel } from 'vs/platform/log/common/log';
import { TaskExecutionDTO, TaskDTO, TaskHandleDTO, TaskFilterDTO, TaskProcessStartedDTO, TaskProcessEndedDTO, TaskSystemInfoDTO } from 'vs/workbench/api/shared/tasks';
import { ITerminalDimensions } from 'vs/workbench/parts/terminal/common/terminal';
export interface IEnvironment {
isExtensionDevelopmentDebug: boolean;
......@@ -339,6 +340,7 @@ export interface MainThreadTerminalServiceShape extends IDisposable {
// Renderer
$terminalRendererSetName(terminalId: number, name: string): void;
$terminalRendererSetDimensions(terminalId: number, dimensions: ITerminalDimensions): void;
$terminalRendererWrite(terminalId: number, text: string): void;
$terminalRendererRegisterOnDataListener(terminalId: number): void;
}
......@@ -843,6 +845,7 @@ export interface ExtHostTerminalServiceShape {
$acceptTerminalProcessId(id: number, processId: number): void;
$acceptTerminalProcessData(id: number, data: string): void;
$acceptTerminalRendererData(id: number, data: string): void;
$acceptTerminalRendererDimensions(id: number, cols: number, rows: number): void;
$createProcess(id: number, shellLaunchConfig: ShellLaunchConfigDto, cols: number, rows: number): void;
$acceptProcessInput(id: number, data: string): void;
$acceptProcessResize(id: number, cols: number, rows: number): void;
......
......@@ -150,12 +150,37 @@ export class ExtHostTerminalRenderer extends BaseExtHostTerminal implements vsco
return this._onData && this._onData.event;
}
private _dimensions: vscode.TerminalDimensions | undefined;
public get dimensions(): vscode.TerminalDimensions { return this._dimensions; }
public set dimensions(dimensions: vscode.TerminalDimensions) {
this._checkDisposed();
this._dimensions = dimensions;
this._queueApiRequest(this._proxy.$terminalRendererSetDimensions, [dimensions]);
// TODO: Send overridden dimensions over to the terminal instance
}
private _maximumDimensions: vscode.TerminalDimensions;
public get maximumDimensions(): vscode.TerminalDimensions {
if (!this._maximumDimensions) {
return undefined;
}
return {
rows: this._maximumDimensions.rows,
cols: this._maximumDimensions.cols
};
}
private readonly _onDidChangeMaximumDimensions: Emitter<vscode.TerminalDimensions> = new Emitter<vscode.TerminalDimensions>();
public get onDidChangeMaximumDimensions(): Event<vscode.TerminalDimensions> {
return this._onDidChangeMaximumDimensions && this._onDidChangeMaximumDimensions.event;
}
constructor(
proxy: MainThreadTerminalServiceShape,
private _name: string
) {
super(proxy);
this._proxy.$createTerminalRenderer(this._name).then((id) => {
this._proxy.$createTerminalRenderer(this._name).then(id => {
this._runQueuedRequests(id);
});
}
......@@ -168,6 +193,11 @@ export class ExtHostTerminalRenderer extends BaseExtHostTerminal implements vsco
public _fireOnData(data: string): void {
this._onData.fire(data);
}
public _setMaximumDimensions(cols: number, rows: number): void {
this._maximumDimensions = { cols, rows };
this._onDidChangeMaximumDimensions.fire(this.maximumDimensions);
}
}
export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
......@@ -221,6 +251,15 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
terminal._fireOnData(data);
}
public $acceptTerminalRendererDimensions(id: number, cols: number, rows: number): void {
const index = this._getTerminalRendererIndexById(id);
if (index === null) {
return;
}
const renderer = this._terminalRenderers[index];
renderer._setMaximumDimensions(cols, rows);
}
public $acceptTerminalRendererData(id: number, data: string): void {
const index = this._getTerminalRendererIndexById(id);
if (index === null) {
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
......@@ -176,6 +176,7 @@ export interface ITerminalService {
onInstanceCreated: Event<ITerminalInstance>;
onInstanceDisposed: Event<ITerminalInstance>;
onInstanceProcessIdReady: Event<ITerminalInstance>;
onInstanceDimensionsChanged: Event<ITerminalInstance>;
onInstanceRequestExtHostProcess: Event<ITerminalProcessExtHostRequest>;
onInstancesChanged: Event<void>;
onInstanceTitleChanged: Event<string>;
......@@ -250,12 +251,27 @@ export interface ITerminalTab {
split(terminalFocusContextKey: IContextKey<boolean>, configHelper: ITerminalConfigHelper, shellLaunchConfig: IShellLaunchConfig): ITerminalInstance;
}
export interface ITerminalDimensions {
/**
* The columns of the terminal.
*/
readonly cols: number;
/**
* The rows of the terminal.
*/
readonly rows: number;
}
export interface ITerminalInstance {
/**
* The ID of the terminal instance, this is an arbitrary number only used to identify the
* terminal instance.
*/
id: number;
readonly id: number;
readonly cols: number;
readonly rows: number;
/**
* The process ID of the shell process, this is undefined when there is no process associated
......@@ -279,6 +295,8 @@ export interface ITerminalInstance {
onRequestExtHostProcess: Event<ITerminalInstance>;
onDimensionsChanged: Event<void>;
processReady: TPromise<void>;
/**
......@@ -511,6 +529,8 @@ export interface ITerminalInstance {
*/
setTitle(title: string, eventFromProcess: boolean): void;
setDimensions(dimensions: ITerminalDimensions): void;
addDisposable(disposable: IDisposable): void;
}
......
......@@ -41,6 +41,8 @@ export abstract class TerminalService implements ITerminalService {
public get onInstanceProcessIdReady(): Event<ITerminalInstance> { return this._onInstanceProcessIdReady.event; }
protected readonly _onInstanceRequestExtHostProcess: Emitter<ITerminalProcessExtHostRequest> = new Emitter<ITerminalProcessExtHostRequest>();
public get onInstanceRequestExtHostProcess(): Event<ITerminalProcessExtHostRequest> { return this._onInstanceRequestExtHostProcess.event; }
protected readonly _onInstanceDimensionsChanged: Emitter<ITerminalInstance> = new Emitter<ITerminalInstance>();
public get onInstanceDimensionsChanged(): Event<ITerminalInstance> { return this._onInstanceDimensionsChanged.event; }
protected readonly _onInstancesChanged: Emitter<void> = new Emitter<void>();
public get onInstancesChanged(): Event<void> { return this._onInstancesChanged.event; }
protected readonly _onInstanceTitleChanged: Emitter<string> = new Emitter<string>();
......@@ -288,6 +290,7 @@ export abstract class TerminalService implements ITerminalService {
instance.addDisposable(instance.onDisposed(this._onInstanceDisposed.fire, this._onInstanceDisposed));
instance.addDisposable(instance.onTitleChanged(this._onInstanceTitleChanged.fire, this._onInstanceTitleChanged));
instance.addDisposable(instance.onProcessIdReady(this._onInstanceProcessIdReady.fire, this._onInstanceProcessIdReady));
instance.addDisposable(instance.onDimensionsChanged(() => this._onInstanceDimensionsChanged.fire(instance)));
}
private _getTabForInstance(instance: ITerminalInstance): ITerminalTab {
......
......@@ -14,7 +14,7 @@ import { Terminal as XTermTerminal } from 'vscode-xterm';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { ITerminalInstance, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_PANEL_ID, IShellLaunchConfig, ITerminalProcessManager, ProcessState, NEVER_MEASURE_RENDER_TIME_STORAGE_KEY } from 'vs/workbench/parts/terminal/common/terminal';
import { ITerminalInstance, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_PANEL_ID, IShellLaunchConfig, ITerminalProcessManager, ProcessState, NEVER_MEASURE_RENDER_TIME_STORAGE_KEY, ITerminalDimensions } from 'vs/workbench/parts/terminal/common/terminal';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { TabFocus } from 'vs/editor/common/config/commonEditorConfig';
......@@ -63,6 +63,7 @@ export class TerminalInstance implements ITerminalInstance {
private _terminalHasTextContextKey: IContextKey<boolean>;
private _cols: number;
private _rows: number;
private _dimensionsOverride: ITerminalDimensions;
private _windowsShellHelper: WindowsShellHelper;
private _onLineDataListeners: ((lineData: string) => void)[];
private _xtermReadyPromise: TPromise<void>;
......@@ -76,6 +77,8 @@ 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; }
// 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?
......@@ -97,6 +100,8 @@ export class TerminalInstance implements ITerminalInstance {
public get onTitleChanged(): Event<string> { return this._onTitleChanged.event; }
private readonly _onRequestExtHostProcess: Emitter<ITerminalInstance> = new Emitter<ITerminalInstance>();
public get onRequestExtHostProcess(): Event<ITerminalInstance> { return this._onRequestExtHostProcess.event; }
private readonly _onDimensionsChanged: Emitter<void> = new Emitter<void>();
public get onDimensionsChanged(): Event<void> { return this._onDimensionsChanged.event; }
public constructor(
private readonly _terminalFocusContextKey: IContextKey<boolean>,
......@@ -930,6 +935,21 @@ export class TerminalInstance implements ITerminalInstance {
return;
}
if (this._xterm) {
this._xterm.element.style.width = terminalWidth + 'px';
}
this._resize();
}
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), this._cols);
rows = Math.min(Math.max(this._dimensionsOverride.rows, 2), this._rows);
}
if (this._xterm) {
const font = this._configHelper.getFont(this._xterm);
......@@ -946,8 +966,11 @@ export class TerminalInstance implements ITerminalInstance {
this._safeSetOption('drawBoldTextInBrightColors', config.drawBoldTextInBrightColors);
}
this._xterm.resize(this._cols, this._rows);
this._xterm.element.style.width = terminalWidth + 'px';
if (cols !== this._xterm.getOption('cols') || rows !== this._xterm.getOption('rows')) {
this._onDimensionsChanged.fire();
}
this._xterm.resize(cols, rows);
if (this._isVisible) {
// Force the renderer to unpause by simulating an IntersectionObserver event. This
// is to fix an issue where dragging the window to the top of the screen to maximize
......@@ -960,7 +983,7 @@ export class TerminalInstance implements ITerminalInstance {
}
if (this._processManager) {
this._processManager.ptyProcessReady.then(() => this._processManager.setDimensions(this._cols, this._rows));
this._processManager.ptyProcessReady.then(() => this._processManager.setDimensions(cols, rows));
}
}
......@@ -989,6 +1012,11 @@ export class TerminalInstance implements ITerminalInstance {
}
}
public setDimensions(dimensions: ITerminalDimensions): void {
this._dimensionsOverride = dimensions;
this._resize();
}
private _getXtermTheme(theme?: ITheme): any {
if (!theme) {
theme = this._themeService.getTheme();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册